<commit_before>use core::marker::PhantomData;
use core::{mem, ptr};
use core::num::Wrapping as W;
use core::ops::{Shl, BitXor, Mul};

use static_buffer::{FixedBuffer64, FixedBuffer128, FixedBuf};
use byteorder::{ByteOrder, LittleEndian};
use generic_array::ArrayLength;
use typenum::uint::Unsigned;
use typenum::consts::{U8, U16, U20, U28, U32, U48, U64, U128};

use Digest;

const BLAKE2S_INIT: [W<u32>; 8] = [W(0x6a09e667),
                                   W(0xbb67ae85),
                                   W(0x3c6ef372),
                                   W(0xa54ff53a),
                                   W(0x510e527f),
                                   W(0x9b05688c),
                                   W(0x1f83d9ab),
                                   W(0x5be0cd19)];
const BLAKE2B_INIT: [W<u64>; 8] = [W(0x6a09e667f3bcc908),
                                   W(0xbb67ae8584caa73b),
                                   W(0x3c6ef372fe94f82b),
                                   W(0xa54ff53a5f1d36f1),
                                   W(0x510e527fade682d1),
                                   W(0x9b05688c2b3e6c1f),
                                   W(0x1f83d9abfb41bd6b),
                                   W(0x5be0cd19137e2179)];

const SIGMA: [[usize; 16]; 12] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
                                  [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
                                  [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
                                  [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
                                  [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
                                  [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
                                  [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
                                  [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
                                  [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
                                  [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
                                  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
                                  [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]];

macro_rules! G {
    ($v:ident, $a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $y:expr) => {
        $v[$a] = $v[$a] + $v[$b] + $x;
        $v[$d] = W(($v[$d] ^ $v[$a]).0.rotate_right(R1));
        $v[$c] = $v[$c] + $v[$d];
        $v[$b] = W(($v[$b] ^ $v[$c]).0.rotate_right(R2));
        $v[$a] = $v[$a] + $v[$b] + $y;
        $v[$d] = W(($v[$d] ^ $v[$a]).0.rotate_right(R3));
        $v[$c] = $v[$c] + $v[$d];
        $v[$b] = W(($v[$b] ^ $v[$c]).0.rotate_right(R4));
    }
}

#[derive(Copy, Clone, Debug)]
struct State<Word: Copy> {
    h: [W<Word>; 8],
}

impl<Word> State<Word>
    where Word: From<u8> + From<u32> + Copy + BitXor<Output = Word> + Shl<usize, Output = Word> + Default
{
    fn new(mut state: [W<Word>; 8], key_size: u8, size: u8) -> Self {
        state[0] = W(state[0].0 ^ 0x1010000u32.into() ^ ((key_size as u32) << 8).into() ^ size.into());

        State { h: state }
    }
}

macro_rules! blake2_state {
    ($word:ty, $read:ident, $init:ident, $rounds:expr, $r1:expr, $r2:expr, $r3:expr, $r4:expr) => {
        impl State<$word> {
            fn compress(&mut self, input: &[u8], len: Length<$word>, last: bool) {
                const R1: u32 = $r1;
                const R2: u32 = $r2;
                const R3: u32 = $r3;
                const R4: u32 = $r4;

                let word_bytes = mem::size_of::<$word>();

                let mut message = [W(0); 16];
                for (word, chunk) in message.iter_mut().zip(input.chunks(word_bytes)) {
                    *word = W(LittleEndian::$read(chunk));
                }

                let mut v = [W(0); 16];
                for (v, state) in v.iter_mut().take(8).zip(&self.h) {
                    *v = *state;
                }
                for (v, iv) in v.iter_mut().skip(8).zip(&$init) {
                    *v = *iv;
                }
                v[12].0 ^= len.0;
                v[13].0 ^= len.1;
                if last {
                    v[14] = !v[14];
                }

                for sigma in &SIGMA[..$rounds] {
                    G!(v, 0, 4, 8,  12, message[sigma[0]],  message[sigma[1]]);
                    G!(v, 1, 5, 9,  13, message[sigma[2]],  message[sigma[3]]);
                    G!(v, 2, 6, 10, 14, message[sigma[4]],  message[sigma[5]]);
                    G!(v, 3, 7, 11, 15, message[sigma[6]],  message[sigma[7]]);

                    G!(v, 0, 5, 10, 15, message[sigma[8]],  message[sigma[9]]);
                    G!(v, 1, 6, 11, 12, message[sigma[10]], message[sigma[11]]);
                    G!(v, 2, 7, 8,  13, message[sigma[12]], message[sigma[13]]);
                    G!(v, 3, 4, 9,  14, message[sigma[14]], message[sigma[15]]);
                }

                for i in 0..8 {
                    self.h[i] = self.h[i] ^ v[i] ^ v[i + 8];
                }
            }
        }
    }
}

blake2_state!(u32, read_u32, BLAKE2S_INIT, 10, 16, 12, 8, 7);
blake2_state!(u64, read_u64, BLAKE2B_INIT, 12, 32, 24, 16, 63);

#[derive(Copy, Clone, Debug)]
struct Length<T>(T, T);

impl Length<u32> {
    fn increment(&mut self, val: usize) {
        let (val, over) = self.0.overflowing_add(val as u32);
        self.0 = val;
        if over {
            self.1 += 1
        }
    }
}

impl Length<u64> {
    fn increment(&mut self, val: usize) {
        let (val, over) = self.0.overflowing_add(val as u64);
        self.0 = val;
        if over {
            self.1 += 1
        }
    }
}

macro_rules! blake2 {
    ($name:ident<$word:ty>, $init:ident, $buf:ty, $bsize:ty) => {
        #[derive(Clone)]
        pub struct $name<Size: Unsigned + Clone> {
            state: State<$word>,
            len: Length<$word>,
            buffer: $buf,
            _phantom: PhantomData<Size>,
        }

        impl<Size: Unsigned + Clone> $name<Size> {
            pub fn with_key<K: AsRef<[u8]>>(key: K) -> Self {
                let key = key.as_ref();

                let mut ret = $name {
                    state: State::new($init, key.len() as u8, Size::to_u8()),
                    len: Length(0, 0),
                    buffer: <$buf>::new(),
                    _phantom: PhantomData
                };

                if !key.is_empty() {
                    ret.buffer.input(key, |_| {});
                    ret.buffer.zero_until(<$buf>::size());

                    ret.len.increment(<$buf>::size());
                    ret.state.compress(ret.buffer.full_buffer(),
                                       ret.len,
                                       false);
                }

                ret
            }
        }

        impl<Size: Unsigned + Clone> Default for $name<Size> {
            fn default() -> Self {
                Self::with_key(&[])
            }
        }

        impl<Size> Digest for $name<Size>
            where Size: ArrayLength<u8> + Mul<U8> + Clone,
                  <Size as Mul<U8>>::Output: ArrayLength<u8>
        {
            type OutputBits = <Self::OutputBytes as Mul<U8>>::Output;
            type OutputBytes = Size;
            type BlockSize = $bsize;

            fn update<T: AsRef<[u8]>>(&mut self, input: T) {
                let input = input.as_ref();
                let state = &mut self.state;
                let len = &mut self.len;

                self.buffer.input(&input, |d| {
                    len.increment(d.len());
                    state.compress(d, *len, false);
                })
            }

            fn result<T: AsMut<[u8]>>(mut self, mut out: T) {
                let rest = self.buffer.position();
                self.len.increment(rest);
                self.buffer.zero_until(<$buf>::size());

                self.state.compress(self.buffer.full_buffer(),
                                    self.len,
                                    true);

                let mut out = out.as_mut();
                assert!(out.len() >= Self::output_bytes());

                unsafe {
                    ptr::copy_nonoverlapping(self.state.h.as_ptr() as *const u8,
                                             out.as_mut_ptr(),
                                             Self::output_bytes())
                }
            }
        }
    }
}

blake2!(Blake2s<u32>, BLAKE2S_INIT, FixedBuffer64, U64);
blake2!(Blake2b<u64>, BLAKE2B_INIT, FixedBuffer128, U128);

pub type Blake2b160 = Blake2b<U20>;
pub type Blake2b256 = Blake2b<U32>;
pub type Blake2b384 = Blake2b<U48>;
pub type Blake2b512 = Blake2b<U64>;

pub type Blake2s128 = Blake2s<U16>;
pub type Blake2s160 = Blake2s<U20>;
pub type Blake2s224 = Blake2s<U28>;
pub type Blake2s256 = Blake2s<U32>;
<commit_msg>overflowing_add has been depreciated. This patch fixes the fact that were 2 instances of this method in Length<u32><commit_after>use core::marker::PhantomData;
use core::{mem, ptr};
use core::num::Wrapping as W;
use core::ops::{Shl, BitXor, Mul};

use static_buffer::{FixedBuffer64, FixedBuffer128, FixedBuf};
use byteorder::{ByteOrder, LittleEndian};
use generic_array::ArrayLength;
use typenum::uint::Unsigned;
use typenum::consts::{U8, U16, U20, U28, U32, U48, U64, U128};

use Digest;

const BLAKE2S_INIT: [W<u32>; 8] = [W(0x6a09e667),
                                   W(0xbb67ae85),
                                   W(0x3c6ef372),
                                   W(0xa54ff53a),
                                   W(0x510e527f),
                                   W(0x9b05688c),
                                   W(0x1f83d9ab),
                                   W(0x5be0cd19)];
const BLAKE2B_INIT: [W<u64>; 8] = [W(0x6a09e667f3bcc908),
                                   W(0xbb67ae8584caa73b),
                                   W(0x3c6ef372fe94f82b),
                                   W(0xa54ff53a5f1d36f1),
                                   W(0x510e527fade682d1),
                                   W(0x9b05688c2b3e6c1f),
                                   W(0x1f83d9abfb41bd6b),
                                   W(0x5be0cd19137e2179)];

const SIGMA: [[usize; 16]; 12] = [[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
                                  [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
                                  [11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
                                  [7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
                                  [9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
                                  [2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
                                  [12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
                                  [13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
                                  [6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
                                  [10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
                                  [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
                                  [14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3]];

macro_rules! G {
    ($v:ident, $a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $y:expr) => {
        $v[$a] = $v[$a] + $v[$b] + $x;
        $v[$d] = W(($v[$d] ^ $v[$a]).0.rotate_right(R1));
        $v[$c] = $v[$c] + $v[$d];
        $v[$b] = W(($v[$b] ^ $v[$c]).0.rotate_right(R2));
        $v[$a] = $v[$a] + $v[$b] + $y;
        $v[$d] = W(($v[$d] ^ $v[$a]).0.rotate_right(R3));
        $v[$c] = $v[$c] + $v[$d];
        $v[$b] = W(($v[$b] ^ $v[$c]).0.rotate_right(R4));
    }
}

#[derive(Copy, Clone, Debug)]
struct State<Word: Copy> {
    h: [W<Word>; 8],
}

impl<Word> State<Word>
    where Word: From<u8> + From<u32> + Copy + BitXor<Output = Word> + Shl<usize, Output = Word> + Default
{
    fn new(mut state: [W<Word>; 8], key_size: u8, size: u8) -> Self {
        state[0] = W(state[0].0 ^ 0x1010000u32.into() ^ ((key_size as u32) << 8).into() ^ size.into());

        State { h: state }
    }
}

macro_rules! blake2_state {
    ($word:ty, $read:ident, $init:ident, $rounds:expr, $r1:expr, $r2:expr, $r3:expr, $r4:expr) => {
        impl State<$word> {
            fn compress(&mut self, input: &[u8], len: Length<$word>, last: bool) {
                const R1: u32 = $r1;
                const R2: u32 = $r2;
                const R3: u32 = $r3;
                const R4: u32 = $r4;

                let word_bytes = mem::size_of::<$word>();

                let mut message = [W(0); 16];
                for (word, chunk) in message.iter_mut().zip(input.chunks(word_bytes)) {
                    *word = W(LittleEndian::$read(chunk));
                }

                let mut v = [W(0); 16];
                for (v, state) in v.iter_mut().take(8).zip(&self.h) {
                    *v = *state;
                }
                for (v, iv) in v.iter_mut().skip(8).zip(&$init) {
                    *v = *iv;
                }
                v[12].0 ^= len.0;
                v[13].0 ^= len.1;
                if last {
                    v[14] = !v[14];
                }

                for sigma in &SIGMA[..$rounds] {
                    G!(v, 0, 4, 8,  12, message[sigma[0]],  message[sigma[1]]);
                    G!(v, 1, 5, 9,  13, message[sigma[2]],  message[sigma[3]]);
                    G!(v, 2, 6, 10, 14, message[sigma[4]],  message[sigma[5]]);
                    G!(v, 3, 7, 11, 15, message[sigma[6]],  message[sigma[7]]);

                    G!(v, 0, 5, 10, 15, message[sigma[8]],  message[sigma[9]]);
                    G!(v, 1, 6, 11, 12, message[sigma[10]], message[sigma[11]]);
                    G!(v, 2, 7, 8,  13, message[sigma[12]], message[sigma[13]]);
                    G!(v, 3, 4, 9,  14, message[sigma[14]], message[sigma[15]]);
                }

                for i in 0..8 {
                    self.h[i] = self.h[i] ^ v[i] ^ v[i + 8];
                }
            }
        }
    }
}

blake2_state!(u32, read_u32, BLAKE2S_INIT, 10, 16, 12, 8, 7);
blake2_state!(u64, read_u64, BLAKE2B_INIT, 12, 32, 24, 16, 63);

#[derive(Copy, Clone, Debug)]
struct Length<T>(T, T);

impl Length<u32> {
    fn increment(&mut self, val: usize) {
        self.0.wrapping_add( val as u32 );
    }
}

impl Length<u64> {
    fn increment(&mut self, val: usize) {
        self.0.wrapping_add(val as u64);
    }
}

macro_rules! blake2 {
    ($name:ident<$word:ty>, $init:ident, $buf:ty, $bsize:ty) => {
        #[derive(Clone)]
        pub struct $name<Size: Unsigned + Clone> {
            state: State<$word>,
            len: Length<$word>,
            buffer: $buf,
            _phantom: PhantomData<Size>,
        }

        impl<Size: Unsigned + Clone> $name<Size> {
            pub fn with_key<K: AsRef<[u8]>>(key: K) -> Self {
                let key = key.as_ref();

                let mut ret = $name {
                    state: State::new($init, key.len() as u8, Size::to_u8()),
                    len: Length(0, 0),
                    buffer: <$buf>::new(),
                    _phantom: PhantomData
                };

                if !key.is_empty() {
                    ret.buffer.input(key, |_| {});
                    ret.buffer.zero_until(<$buf>::size());

                    ret.len.increment(<$buf>::size());
                    ret.state.compress(ret.buffer.full_buffer(),
                                       ret.len,
                                       false);
                }

                ret
            }
        }

        impl<Size: Unsigned + Clone> Default for $name<Size> {
            fn default() -> Self {
                Self::with_key(&[])
            }
        }

        impl<Size> Digest for $name<Size>
            where Size: ArrayLength<u8> + Mul<U8> + Clone,
                  <Size as Mul<U8>>::Output: ArrayLength<u8>
        {
            type OutputBits = <Self::OutputBytes as Mul<U8>>::Output;
            type OutputBytes = Size;
            type BlockSize = $bsize;

            fn update<T: AsRef<[u8]>>(&mut self, input: T) {
                let input = input.as_ref();
                let state = &mut self.state;
                let len = &mut self.len;

                self.buffer.input(&input, |d| {
                    len.increment(d.len());
                    state.compress(d, *len, false);
                })
            }

            fn result<T: AsMut<[u8]>>(mut self, mut out: T) {
                let rest = self.buffer.position();
                self.len.increment(rest);
                self.buffer.zero_until(<$buf>::size());

                self.state.compress(self.buffer.full_buffer(),
                                    self.len,
                                    true);

                let mut out = out.as_mut();
                assert!(out.len() >= Self::output_bytes());

                unsafe {
                    ptr::copy_nonoverlapping(self.state.h.as_ptr() as *const u8,
                                             out.as_mut_ptr(),
                                             Self::output_bytes())
                }
            }
        }
    }
}

blake2!(Blake2s<u32>, BLAKE2S_INIT, FixedBuffer64, U64);
blake2!(Blake2b<u64>, BLAKE2B_INIT, FixedBuffer128, U128);

pub type Blake2b160 = Blake2b<U20>;
pub type Blake2b256 = Blake2b<U32>;
pub type Blake2b384 = Blake2b<U48>;
pub type Blake2b512 = Blake2b<U64>;

pub type Blake2s128 = Blake2s<U16>;
pub type Blake2s160 = Blake2s<U20>;
pub type Blake2s224 = Blake2s<U28>;
pub type Blake2s256 = Blake2s<U32>;
<|endoftext|>


<commit_before>use super::clock::Clock;
use super::error::Result;
use super::master::Master;
use super::slave::Slave;
use rosxmlrpc::Response;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use tcpros::{Message, PublisherStream, ServicePair, ServiceResult};

#[derive(Clone)]
pub struct Publisher<T: Message> {
    clock: Arc<Clock>,
    seq: Arc<AtomicUsize>,
    stream: PublisherStream<T>,
    _raii: Arc<InteractorRaii<PublisherInfo>>,
}

impl<T: Message> Publisher<T> {
    pub(crate) fn new(
        master: Arc<Master>,
        slave: Arc<Slave>,
        clock: Arc<Clock>,
        hostname: &str,
        name: &str,
    ) -> Result<Self> {
        let stream = slave.add_publication::<T>(hostname, name)?;
        let mut info = PublisherInfo {
            master,
            slave,
            name: name.into(),
        };

        match info.master.register_publisher(name, &T::msg_type()) {
            Ok(_) => Ok(Self {
                stream,
                clock,
                seq: Arc::new(AtomicUsize::new(0)),
                _raii: Arc::new(InteractorRaii::new(info)),
            }),
            Err(error) => {
                error!(
                    "Failed to register publisher for topic '{}': {}",
                    name, error
                );
                info.unregister()?;
                Err(error.into())
            }
        }
    }

    #[inline]
    pub fn set_latching(&mut self, latching: bool) {
        self.stream.set_latching(latching);
    }

    #[inline]
    pub fn set_queue_size(&mut self, queue_size: Option<usize>) {
        self.stream.set_queue_size(queue_size);
    }

    #[inline]
    pub fn send(&mut self, mut message: T) -> Result<()> {
        message.set_header(&self.clock, &self.seq);
        self.stream.send(&message).map_err(|v| v.into())
    }
}

struct PublisherInfo {
    master: Arc<Master>,
    slave: Arc<Slave>,
    name: String,
}

impl Interactor for PublisherInfo {
    fn unregister(&mut self) -> Response<()> {
        self.slave.remove_publication(&self.name);
        self.master.unregister_publisher(&self.name).map(|_| ())
    }
}

#[derive(Clone)]
pub struct Subscriber {
    _raii: Arc<InteractorRaii<SubscriberInfo>>,
}

impl Subscriber {
    pub(crate) fn new<T: Message, F: Fn(T) -> () + Send + 'static>(
        master: Arc<Master>,
        slave: Arc<Slave>,
        name: &str,
        callback: F,
    ) -> Result<Self> {
        slave.add_subscription::<T, F>(name, callback)?;

        match master.register_subscriber(name, &T::msg_type()) {
            Ok(publishers) => {
                if let Err(err) = slave.add_publishers_to_subscription(name, publishers.into_iter())
                {
                    error!(
                        "Failed to subscribe to all publishers of topic '{}': {}",
                        name, err
                    );
                }
                Ok(Self {
                    _raii: Arc::new(InteractorRaii::new(SubscriberInfo {
                        master,
                        slave,
                        name: name.into(),
                    })),
                })
            }
            Err(err) => {
                SubscriberInfo {
                    master,
                    slave,
                    name: name.into(),
                }.unregister()?;
                Err(err.into())
            }
        }
    }
}

struct SubscriberInfo {
    master: Arc<Master>,
    slave: Arc<Slave>,
    name: String,
}

impl Interactor for SubscriberInfo {
    fn unregister(&mut self) -> Response<()> {
        self.slave.remove_subscription(&self.name);
        self.master.unregister_subscriber(&self.name).map(|_| ())
    }
}

#[derive(Clone)]
pub struct Service {
    _raii: Arc<InteractorRaii<ServiceInfo>>,
}

impl Service {
    pub(crate) fn new<T, F>(
        master: Arc<Master>,
        slave: Arc<Slave>,
        hostname: &str,
        name: &str,
        handler: F,
    ) -> Result<Self>
    where
        T: ServicePair,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let api = slave.add_service::<T, F>(hostname, name, handler)?;

        let mut info = ServiceInfo {
            master,
            slave,
            api,
            name: name.into(),
        };

        if let Err(err) = info.master.register_service(name, &info.api) {
            info.unregister()?;
            Err(err.into())
        } else {
            Ok(Self {
                _raii: Arc::new(InteractorRaii::new(info)),
            })
        }
    }
}

struct ServiceInfo {
    master: Arc<Master>,
    slave: Arc<Slave>,
    name: String,
    api: String,
}

impl Interactor for ServiceInfo {
    fn unregister(&mut self) -> Response<()> {
        self.slave.remove_service(&self.name);
        self.master
            .unregister_service(&self.name, &self.api)
            .map(|_| ())
    }
}

trait Interactor {
    fn unregister(&mut self) -> Response<()>;
}

struct InteractorRaii<I: Interactor> {
    interactor: I,
}

impl<I: Interactor> InteractorRaii<I> {
    pub fn new(interactor: I) -> InteractorRaii<I> {
        Self { interactor }
    }
}

impl<I: Interactor> Drop for InteractorRaii<I> {
    fn drop(&mut self) {
        if let Err(e) = self.interactor.unregister() {
            error!("Error while unloading: {:?}", e);
        }
    }
}
<commit_msg>Always use RAII for deregistering<commit_after>use super::clock::Clock;
use super::error::Result;
use super::master::Master;
use super::slave::Slave;
use rosxmlrpc::Response;
use std::sync::atomic::AtomicUsize;
use std::sync::Arc;
use tcpros::{Message, PublisherStream, ServicePair, ServiceResult};

#[derive(Clone)]
pub struct Publisher<T: Message> {
    clock: Arc<Clock>,
    seq: Arc<AtomicUsize>,
    stream: PublisherStream<T>,
    _raii: Arc<InteractorRaii<PublisherInfo>>,
}

impl<T: Message> Publisher<T> {
    pub(crate) fn new(
        master: Arc<Master>,
        slave: Arc<Slave>,
        clock: Arc<Clock>,
        hostname: &str,
        name: &str,
    ) -> Result<Self> {
        let stream = slave.add_publication::<T>(hostname, name)?;

        let raii = Arc::new(InteractorRaii::new(PublisherInfo {
            master,
            slave,
            name: name.into(),
        }));

        raii.interactor
            .master
            .register_publisher(name, &T::msg_type())
            .map_err(|err| {
                error!("Failed to register publisher for topic '{}': {}", name, err);
                err
            })?;

        Ok(Self {
            stream,
            clock,
            seq: Arc::new(AtomicUsize::new(0)),
            _raii: raii,
        })
    }

    #[inline]
    pub fn set_latching(&mut self, latching: bool) {
        self.stream.set_latching(latching);
    }

    #[inline]
    pub fn set_queue_size(&mut self, queue_size: Option<usize>) {
        self.stream.set_queue_size(queue_size);
    }

    #[inline]
    pub fn send(&mut self, mut message: T) -> Result<()> {
        message.set_header(&self.clock, &self.seq);
        self.stream.send(&message).map_err(|v| v.into())
    }
}

struct PublisherInfo {
    master: Arc<Master>,
    slave: Arc<Slave>,
    name: String,
}

impl Interactor for PublisherInfo {
    fn unregister(&mut self) -> Response<()> {
        self.slave.remove_publication(&self.name);
        self.master.unregister_publisher(&self.name).map(|_| ())
    }
}

#[derive(Clone)]
pub struct Subscriber {
    _raii: Arc<InteractorRaii<SubscriberInfo>>,
}

impl Subscriber {
    pub(crate) fn new<T: Message, F: Fn(T) -> () + Send + 'static>(
        master: Arc<Master>,
        slave: Arc<Slave>,
        name: &str,
        callback: F,
    ) -> Result<Self> {
        slave.add_subscription::<T, F>(name, callback)?;

        let raii = Arc::new(InteractorRaii::new(SubscriberInfo {
            master,
            slave,
            name: name.into(),
        }));

        let publishers = raii
            .interactor
            .master
            .register_subscriber(name, &T::msg_type())?;

        if let Err(err) = raii
            .interactor
            .slave
            .add_publishers_to_subscription(name, publishers.into_iter())
        {
            error!(
                "Failed to subscribe to all publishers of topic '{}': {}",
                name, err
            );
        }

        Ok(Self { _raii: raii })
    }
}

struct SubscriberInfo {
    master: Arc<Master>,
    slave: Arc<Slave>,
    name: String,
}

impl Interactor for SubscriberInfo {
    fn unregister(&mut self) -> Response<()> {
        self.slave.remove_subscription(&self.name);
        self.master.unregister_subscriber(&self.name).map(|_| ())
    }
}

#[derive(Clone)]
pub struct Service {
    _raii: Arc<InteractorRaii<ServiceInfo>>,
}

impl Service {
    pub(crate) fn new<T, F>(
        master: Arc<Master>,
        slave: Arc<Slave>,
        hostname: &str,
        name: &str,
        handler: F,
    ) -> Result<Self>
    where
        T: ServicePair,
        F: Fn(T::Request) -> ServiceResult<T::Response> + Send + Sync + 'static,
    {
        let api = slave.add_service::<T, F>(hostname, name, handler)?;

        let raii = Arc::new(InteractorRaii::new(ServiceInfo {
            master,
            slave,
            api,
            name: name.into(),
        }));

        raii.interactor
            .master
            .register_service(name, &raii.interactor.api)?;
        Ok(Self { _raii: raii })
    }
}

struct ServiceInfo {
    master: Arc<Master>,
    slave: Arc<Slave>,
    name: String,
    api: String,
}

impl Interactor for ServiceInfo {
    fn unregister(&mut self) -> Response<()> {
        self.slave.remove_service(&self.name);
        self.master
            .unregister_service(&self.name, &self.api)
            .map(|_| ())
    }
}

trait Interactor {
    fn unregister(&mut self) -> Response<()>;
}

struct InteractorRaii<I: Interactor> {
    pub interactor: I,
}

impl<I: Interactor> InteractorRaii<I> {
    pub fn new(interactor: I) -> InteractorRaii<I> {
        Self { interactor }
    }
}

impl<I: Interactor> Drop for InteractorRaii<I> {
    fn drop(&mut self) {
        if let Err(e) = self.interactor.unregister() {
            error!("Error while unloading: {:?}", e);
        }
    }
}
<|endoftext|>


<commit_before>//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).

// There are a variety of `#[cfg]`s controlling which targets are involved in
// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
// that, we'll just allow that some unix targets don't use this module at all.
#![allow(dead_code, unused_macros)]

use crate::ffi::CStr;
use crate::marker;
use crate::mem;
use crate::sync::atomic::{self, AtomicUsize, Ordering};

macro_rules! weak {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        static $name: crate::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
            crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
    )
}

pub struct Weak<F> {
    name: &'static str,
    addr: AtomicUsize,
    _marker: marker::PhantomData<F>,
}

impl<F> Weak<F> {
    pub const fn new(name: &'static str) -> Weak<F> {
        Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
    }

    pub fn get(&self) -> Option<F> {
        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
        unsafe {
            // Relaxed is fine here because we fence before reading through the
            // pointer (see the comment below).
            match self.addr.load(Ordering::Relaxed) {
                1 => self.initialize(),
                0 => None,
                addr => {
                    let func = mem::transmute_copy::<usize, F>(&addr);
                    // The caller is presumably going to read through this value
                    // (by calling the function we've dlsymed). This means we'd
                    // need to have loaded it with at least C11's consume
                    // ordering in order to be guaranteed that the data we read
                    // from the pointer isn't from before the pointer was
                    // stored. Rust has no equivalent to memory_order_consume,
                    // so we use an acquire fence (sorry, ARM).
                    //
                    // Now, in practice this likely isn't needed even on CPUs
                    // where relaxed and consume mean different things. The
                    // symbols we're loading are probably present (or not) at
                    // init, and even if they aren't the runtime dynamic loader
                    // is extremely likely have sufficient barriers internally
                    // (possibly implicitly, for example the ones provided by
                    // invoking `mprotect`).
                    //
                    // That said, none of that's *guaranteed*, and so we fence.
                    atomic::fence(Ordering::Acquire);
                    Some(func)
                }
            }
        }
    }

    // Cold because it should only happen during first-time initalization.
    #[cold]
    unsafe fn initialize(&self) -> Option<F> {
        let val = fetch(self.name);
        // This synchronizes with the acquire fence in `get`.
        self.addr.store(val, Ordering::Release);

        match val {
            0 => None,
            addr => Some(mem::transmute_copy::<usize, F>(&addr)),
        }
    }
}

unsafe fn fetch(name: &str) -> usize {
    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
        Ok(cstr) => cstr,
        Err(..) => return 0,
    };
    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name: $t),*) -> $ret {
            use super::os;

            weak! { fn $name($($t),*) -> $ret }

            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                os::set_errno(libc::ENOSYS);
                -1
            }
        }
    )
}

#[cfg(any(target_os = "linux", target_os = "android"))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name:$t),*) -> $ret {
            // This looks like a hack, but concat_idents only accepts idents
            // (not paths).
            use libc::*;

            weak! { fn $name($($t),*) -> $ret }

            // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
            // interposition, but if it's not found just use a raw syscall.
            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                syscall(
                    concat_idents!(SYS_, $name),
                    $($arg_name as c_long),*
                ) as $ret
            }
        }
    )
}
<commit_msg>unix/weak: pass arguments to syscall at the given type<commit_after>//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).

// There are a variety of `#[cfg]`s controlling which targets are involved in
// each instance of `weak!` and `syscall!`. Rather than trying to unify all of
// that, we'll just allow that some unix targets don't use this module at all.
#![allow(dead_code, unused_macros)]

use crate::ffi::CStr;
use crate::marker;
use crate::mem;
use crate::sync::atomic::{self, AtomicUsize, Ordering};

macro_rules! weak {
    (fn $name:ident($($t:ty),*) -> $ret:ty) => (
        static $name: crate::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
            crate::sys::weak::Weak::new(concat!(stringify!($name), '\0'));
    )
}

pub struct Weak<F> {
    name: &'static str,
    addr: AtomicUsize,
    _marker: marker::PhantomData<F>,
}

impl<F> Weak<F> {
    pub const fn new(name: &'static str) -> Weak<F> {
        Weak { name, addr: AtomicUsize::new(1), _marker: marker::PhantomData }
    }

    pub fn get(&self) -> Option<F> {
        assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
        unsafe {
            // Relaxed is fine here because we fence before reading through the
            // pointer (see the comment below).
            match self.addr.load(Ordering::Relaxed) {
                1 => self.initialize(),
                0 => None,
                addr => {
                    let func = mem::transmute_copy::<usize, F>(&addr);
                    // The caller is presumably going to read through this value
                    // (by calling the function we've dlsymed). This means we'd
                    // need to have loaded it with at least C11's consume
                    // ordering in order to be guaranteed that the data we read
                    // from the pointer isn't from before the pointer was
                    // stored. Rust has no equivalent to memory_order_consume,
                    // so we use an acquire fence (sorry, ARM).
                    //
                    // Now, in practice this likely isn't needed even on CPUs
                    // where relaxed and consume mean different things. The
                    // symbols we're loading are probably present (or not) at
                    // init, and even if they aren't the runtime dynamic loader
                    // is extremely likely have sufficient barriers internally
                    // (possibly implicitly, for example the ones provided by
                    // invoking `mprotect`).
                    //
                    // That said, none of that's *guaranteed*, and so we fence.
                    atomic::fence(Ordering::Acquire);
                    Some(func)
                }
            }
        }
    }

    // Cold because it should only happen during first-time initalization.
    #[cold]
    unsafe fn initialize(&self) -> Option<F> {
        let val = fetch(self.name);
        // This synchronizes with the acquire fence in `get`.
        self.addr.store(val, Ordering::Release);

        match val {
            0 => None,
            addr => Some(mem::transmute_copy::<usize, F>(&addr)),
        }
    }
}

unsafe fn fetch(name: &str) -> usize {
    let name = match CStr::from_bytes_with_nul(name.as_bytes()) {
        Ok(cstr) => cstr,
        Err(..) => return 0,
    };
    libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr()) as usize
}

#[cfg(not(any(target_os = "linux", target_os = "android")))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name: $t),*) -> $ret {
            use super::os;

            weak! { fn $name($($t),*) -> $ret }

            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                os::set_errno(libc::ENOSYS);
                -1
            }
        }
    )
}

#[cfg(any(target_os = "linux", target_os = "android"))]
macro_rules! syscall {
    (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => (
        unsafe fn $name($($arg_name:$t),*) -> $ret {
            // This looks like a hack, but concat_idents only accepts idents
            // (not paths).
            use libc::*;

            weak! { fn $name($($t),*) -> $ret }

            // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
            // interposition, but if it's not found just use a raw syscall.
            if let Some(fun) = $name.get() {
                fun($($arg_name),*)
            } else {
                syscall(
                    concat_idents!(SYS_, $name),
                    $($arg_name),*
                ) as $ret
            }
        }
    )
}
<|endoftext|>


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

use std::cell::Cell;
use std::default::Default;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};
use std::{env, fs};

use regex::Regex;

#[macro_use]
mod config_type;
#[macro_use]
mod options;

pub mod file_lines;
pub mod license;
pub mod lists;
pub mod summary;

use config::config_type::ConfigType;
use config::file_lines::FileLines;
pub use config::lists::*;
pub use config::options::*;
use config::summary::Summary;

/// This macro defines configuration options used in rustfmt. Each option
/// is defined as follows:
///
/// `name: value type, default value, is stable, description;`
create_config! {
    // Fundamental stuff
    max_width: usize, 100, true, "Maximum width of each line";
    hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
    tab_spaces: usize, 4, true, "Number of spaces per tab";
    newline_style: NewlineStyle, NewlineStyle::Unix, true, "Unix or Windows line endings";
    indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items.";
    use_small_heuristics: bool, true, false, "Whether to use different formatting for items and \
        expressions if they satisfy a heuristic notion of 'small'.";

    // strings and comments
    format_strings: bool, false, false, "Format string literals where necessary";
    wrap_comments: bool, false, true, "Break comments to fit on the line";
    comment_width: usize, 80, false,
        "Maximum length of comments. No effect unless wrap_comments = true";
    normalize_comments: bool, false, true, "Convert /* */ comments to // comments where possible";
    license_template_path: String, String::default(), false, "Beginning of file must match license template";

    // Single line expressions and items.
    empty_item_single_line: bool, true, false,
        "Put empty-body functions and impls on a single line";
    struct_lit_single_line: bool, true, false,
        "Put small struct literals on a single line";
    fn_single_line: bool, false, false, "Put single-expression functions on a single line";
    where_single_line: bool, false, false, "Force where clauses to be on a single line";

    // Imports
    imports_indent: IndentStyle, IndentStyle::Visual, false, "Indent of imports";
    imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";

    // Ordering
    reorder_extern_crates: bool, true, false, "Reorder extern crate statements alphabetically";
    reorder_extern_crates_in_group: bool, true, false, "Reorder extern crate statements in group";
    reorder_imports: bool, true, false, "Reorder import statements alphabetically";
    reorder_imports_in_group: bool, true, false, "Reorder import statements in group";
    reorder_imported_names: bool, true, false,
        "Reorder lists of names in import statements alphabetically";
    reorder_modules: bool, true, false, "Reorder module statemtents alphabetically in group";
    reorder_impl_items: bool, false, false, "Reorder impl items";

    // Spaces around punctuation
    binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
        "Where to put a binary operator when a binary expression goes multiline.";
    type_punctuation_density: TypeDensity, TypeDensity::Wide, false,
        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
    space_before_colon: bool, false, false, "Leave a space before the colon";
    space_after_colon: bool, true, false, "Leave a space after the colon";
    spaces_around_ranges: bool, false, false, "Put spaces around the  .. and ... range operators";
    spaces_within_parens_and_brackets: bool, false, false,
        "Put spaces within non-empty parentheses or brackets";

    // Misc.
    combine_control_expr: bool, true, false, "Combine control expressions with function calls.";
    struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \
                                             threshold.";
    remove_blank_lines_at_start_or_end_of_block: bool, true, false,
        "Remove blank lines at start or end of a block";
    match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
        the same line with the pattern of arms";
    force_multiline_blocks: bool, false, false,
        "Force multiline closure bodies and match arms to be wrapped in a block";
    fn_args_density: Density, Density::Tall, false, "Argument density in functions";
    brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
    control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
        "Brace style for control flow constructs";
    trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
        "How to handle trailing commas for lists";
    trailing_semicolon: bool, true, false,
        "Add trailing semicolon after break, continue and return";
    match_block_trailing_comma: bool, false, false,
        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
    blank_lines_upper_bound: usize, 1, false,
        "Maximum number of blank lines which can be put between items.";
    blank_lines_lower_bound: usize, 0, false,
        "Minimum number of blank lines which must be put between items.";

    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
    merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
    use_try_shorthand: bool, false, false, "Replace uses of the try! macro by the ? shorthand";
    condense_wildcard_suffixes: bool, false, false, "Replace strings of _ wildcards by a single .. \
                                              in tuple patterns";
    force_explicit_abi: bool, true, true, "Always print the abi for extern items";
    use_field_init_shorthand: bool, false, false, "Use field initialization shorthand if possible";

    // Control options (changes the operation of rustfmt, rather than the formatting)
    write_mode: WriteMode, WriteMode::Overwrite, false,
        "What Write Mode to use when none is supplied: \
         Replace, Overwrite, Display, Plain, Diff, Coverage";
    color: Color, Color::Auto, false,
        "What Color option to use when none is supplied: Always, Never, Auto";
    required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
        "Require a specific version of rustfmt.";
    unstable_features: bool, false, true,
            "Enables unstable features. Only available on nightly channel";
    disable_all_formatting: bool, false, false, "Don't reformat anything";
    skip_children: bool, false, false, "Don't reformat out of line modules";
    hide_parse_errors: bool, false, false, "Hide errors from the parser";
    error_on_line_overflow: bool, true, false, "Error if unable to get all lines within max_width";
    error_on_unformatted: bool, false, false,
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces";
    report_todo: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of TODO in source file comments";
    report_fixme: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of FIXME in source file comments";
    ignore: IgnoreList, IgnoreList::default(), false,
        "Skip formatting the specified files and directories.";

    // Not user-facing.
    verbose: bool, false, false, "Use verbose output";
    file_lines: FileLines, FileLines::all(), false,
        "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
         via the --file-lines option";
    width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
        "'small' heuristic values";
}

/// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
///
/// Return the path if a config file exists, empty if no file exists, and Error for IO errors
pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
    const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
    for config_file_name in &CONFIG_FILE_NAMES {
        let config_file = dir.join(config_file_name);
        match fs::metadata(&config_file) {
            // Only return if it's a file to handle the unlikely situation of a directory named
            // `rustfmt.toml`.
            Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
            // Return the error if it's something other than `NotFound`; otherwise we didn't
            // find the project file yet, and continue searching.
            Err(e) => {
                if e.kind() != ErrorKind::NotFound {
                    return Err(e);
                }
            }
            _ => {}
        }
    }
    Ok(None)
}

#[cfg(test)]
mod test {
    use super::Config;

    #[test]
    fn test_config_set() {
        let mut config = Config::default();
        config.set().verbose(false);
        assert_eq!(config.verbose(), false);
        config.set().verbose(true);
        assert_eq!(config.verbose(), true);
    }

    #[test]
    fn test_config_used_to_toml() {
        let config = Config::default();

        let merge_derives = config.merge_derives();
        let skip_children = config.skip_children();

        let used_options = config.used_options();
        let toml = used_options.to_toml().unwrap();
        assert_eq!(
            toml,
            format!(
                "merge_derives = {}\nskip_children = {}\n",
                merge_derives, skip_children,
            )
        );
    }

    #[test]
    fn test_was_set() {
        use std::path::Path;
        let config = Config::from_toml("hard_tabs = true", Path::new("")).unwrap();

        assert_eq!(config.was_set().hard_tabs(), true);
        assert_eq!(config.was_set().verbose(), false);
    }

    // FIXME(#2183) these tests cannot be run in parallel because they use env vars
    // #[test]
    // fn test_as_not_nightly_channel() {
    //     let mut config = Config::default();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    // }

    // #[test]
    // fn test_as_nightly_channel() {
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     let mut config = Config::default();
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }

    // #[test]
    // fn test_unstable_from_toml() {
    //     let mut config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }
}
<commit_msg>Reorder config options<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cell::Cell;
use std::default::Default;
use std::fs::File;
use std::io::{Error, ErrorKind, Read};
use std::path::{Path, PathBuf};
use std::{env, fs};

use regex::Regex;

#[macro_use]
mod config_type;
#[macro_use]
mod options;

pub mod file_lines;
pub mod license;
pub mod lists;
pub mod summary;

use config::config_type::ConfigType;
use config::file_lines::FileLines;
pub use config::lists::*;
pub use config::options::*;
use config::summary::Summary;

/// This macro defines configuration options used in rustfmt. Each option
/// is defined as follows:
///
/// `name: value type, default value, is stable, description;`
create_config! {
    // Fundamental stuff
    max_width: usize, 100, true, "Maximum width of each line";
    hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
    tab_spaces: usize, 4, true, "Number of spaces per tab";
    newline_style: NewlineStyle, NewlineStyle::Unix, true, "Unix or Windows line endings";
    use_small_heuristics: bool, true, false, "Whether to use different formatting for items and \
        expressions if they satisfy a heuristic notion of 'small'.";
    indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items.";

    // Comments and strings
    wrap_comments: bool, false, true, "Break comments to fit on the line";
    comment_width: usize, 80, false,
        "Maximum length of comments. No effect unless wrap_comments = true";
    normalize_comments: bool, false, true, "Convert /* */ comments to // comments where possible";
    license_template_path: String, String::default(), false, "Beginning of file must match license template";
    format_strings: bool, false, false, "Format string literals where necessary";

    // Single line expressions and items
    empty_item_single_line: bool, true, false,
        "Put empty-body functions and impls on a single line";
    struct_lit_single_line: bool, true, false,
        "Put small struct literals on a single line";
    fn_single_line: bool, false, false, "Put single-expression functions on a single line";
    where_single_line: bool, false, false, "Force where clauses to be on a single line";

    // Imports
    imports_indent: IndentStyle, IndentStyle::Visual, false, "Indent of imports";
    imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";

    // Ordering
    reorder_extern_crates: bool, true, false, "Reorder extern crate statements alphabetically";
    reorder_extern_crates_in_group: bool, true, false, "Reorder extern crate statements in group";
    reorder_imports: bool, true, false, "Reorder import statements alphabetically";
    reorder_imports_in_group: bool, true, false, "Reorder import statements in group";
    reorder_imported_names: bool, true, false,
        "Reorder lists of names in import statements alphabetically";
    reorder_modules: bool, true, false, "Reorder module statemtents alphabetically in group";
    reorder_impl_items: bool, false, false, "Reorder impl items";

    // Spaces around punctuation
    type_punctuation_density: TypeDensity, TypeDensity::Wide, false,
        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
    space_before_colon: bool, false, false, "Leave a space before the colon";
    space_after_colon: bool, true, false, "Leave a space after the colon";
    spaces_around_ranges: bool, false, false, "Put spaces around the  .. and ... range operators";
    spaces_within_parens_and_brackets: bool, false, false,
        "Put spaces within non-empty parentheses or brackets";
    binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
        "Where to put a binary operator when a binary expression goes multiline.";

    // Misc.
    remove_blank_lines_at_start_or_end_of_block: bool, true, false,
        "Remove blank lines at start or end of a block";
    combine_control_expr: bool, true, false, "Combine control expressions with function calls.";
    struct_field_align_threshold: usize, 0, false, "Align struct fields if their diffs fits within \
                                             threshold.";
    match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
        the same line with the pattern of arms";
    force_multiline_blocks: bool, false, false,
        "Force multiline closure bodies and match arms to be wrapped in a block";
    fn_args_density: Density, Density::Tall, false, "Argument density in functions";
    brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
    control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
        "Brace style for control flow constructs";
    trailing_semicolon: bool, true, false,
        "Add trailing semicolon after break, continue and return";
    trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
        "How to handle trailing commas for lists";
    match_block_trailing_comma: bool, false, false,
        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
    blank_lines_upper_bound: usize, 1, false,
        "Maximum number of blank lines which can be put between items.";
    blank_lines_lower_bound: usize, 0, false,
        "Minimum number of blank lines which must be put between items.";

    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
    merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
    use_try_shorthand: bool, false, false, "Replace uses of the try! macro by the ? shorthand";
    condense_wildcard_suffixes: bool, false, false, "Replace strings of _ wildcards by a single .. \
                                              in tuple patterns";
    force_explicit_abi: bool, true, true, "Always print the abi for extern items";
    use_field_init_shorthand: bool, false, false, "Use field initialization shorthand if possible";

    // Control options (changes the operation of rustfmt, rather than the formatting)
    write_mode: WriteMode, WriteMode::Overwrite, false,
        "What Write Mode to use when none is supplied: \
         Replace, Overwrite, Display, Plain, Diff, Coverage";
    color: Color, Color::Auto, false,
        "What Color option to use when none is supplied: Always, Never, Auto";
    required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
        "Require a specific version of rustfmt.";
    unstable_features: bool, false, true,
            "Enables unstable features. Only available on nightly channel";
    disable_all_formatting: bool, false, false, "Don't reformat anything";
    skip_children: bool, false, false, "Don't reformat out of line modules";
    hide_parse_errors: bool, false, false, "Hide errors from the parser";
    error_on_line_overflow: bool, true, false, "Error if unable to get all lines within max_width";
    error_on_unformatted: bool, false, false,
        "Error if unable to get comments or string literals within max_width, \
         or they are left with trailing whitespaces";
    report_todo: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of TODO in source file comments";
    report_fixme: ReportTactic, ReportTactic::Never, false,
        "Report all, none or unnumbered occurrences of FIXME in source file comments";
    ignore: IgnoreList, IgnoreList::default(), false,
        "Skip formatting the specified files and directories.";

    // Not user-facing
    verbose: bool, false, false, "Use verbose output";
    file_lines: FileLines, FileLines::all(), false,
        "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
         via the --file-lines option";
    width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
        "'small' heuristic values";
}

/// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
///
/// Return the path if a config file exists, empty if no file exists, and Error for IO errors
pub fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
    const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
    for config_file_name in &CONFIG_FILE_NAMES {
        let config_file = dir.join(config_file_name);
        match fs::metadata(&config_file) {
            // Only return if it's a file to handle the unlikely situation of a directory named
            // `rustfmt.toml`.
            Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
            // Return the error if it's something other than `NotFound`; otherwise we didn't
            // find the project file yet, and continue searching.
            Err(e) => {
                if e.kind() != ErrorKind::NotFound {
                    return Err(e);
                }
            }
            _ => {}
        }
    }
    Ok(None)
}

#[cfg(test)]
mod test {
    use super::Config;

    #[test]
    fn test_config_set() {
        let mut config = Config::default();
        config.set().verbose(false);
        assert_eq!(config.verbose(), false);
        config.set().verbose(true);
        assert_eq!(config.verbose(), true);
    }

    #[test]
    fn test_config_used_to_toml() {
        let config = Config::default();

        let merge_derives = config.merge_derives();
        let skip_children = config.skip_children();

        let used_options = config.used_options();
        let toml = used_options.to_toml().unwrap();
        assert_eq!(
            toml,
            format!(
                "merge_derives = {}\nskip_children = {}\n",
                merge_derives, skip_children,
            )
        );
    }

    #[test]
    fn test_was_set() {
        use std::path::Path;
        let config = Config::from_toml("hard_tabs = true", Path::new("")).unwrap();

        assert_eq!(config.was_set().hard_tabs(), true);
        assert_eq!(config.was_set().verbose(), false);
    }

    // FIXME(#2183) these tests cannot be run in parallel because they use env vars
    // #[test]
    // fn test_as_not_nightly_channel() {
    //     let mut config = Config::default();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    // }

    // #[test]
    // fn test_as_nightly_channel() {
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     let mut config = Config::default();
    //     config.set().unstable_features(true);
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     config.set().unstable_features(true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }

    // #[test]
    // fn test_unstable_from_toml() {
    //     let mut config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), false);
    //     let v = ::std::env::var("CFG_RELEASE_CHANNEL").unwrap_or(String::from(""));
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", "nightly");
    //     config = Config::from_toml("unstable_features = true").unwrap();
    //     assert_eq!(config.was_set().unstable_features(), true);
    //     assert_eq!(config.unstable_features(), true);
    //     ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
    // }
}
<|endoftext|>


<commit_before>//! Semi-internal functionality related to networking.
use std::fmt;

use {hyper, serde_json, serde_ignored};

use futures::{Poll, Future, Stream};
use url::Url;

use {Token, TokenStorage, EndpointType, Error};

/// Struct mirroring `hyper`'s FutureResponse, but with parsing that happens after the request is finished.
#[must_use = "futures do nothing unless polled"]
pub struct FutureResponse<R: EndpointType>(Box<Future<Item = R, Error = Error>>);

impl<R: EndpointType> fmt::Debug for FutureResponse<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ScreepsFutureResponse")
            .field("inner", &"<boxed future>")
            .finish()
    }
}

impl<R> Future for FutureResponse<R>
    where R: EndpointType
{
    type Item = R;
    type Error = Error;

    fn poll(&mut self) -> Poll<R, Error> {
        self.0.poll()
    }
}

/// Interpret a hyper result as the result from a specific endpoint.
///
/// The returned future will:
///
/// - Wait for the hyper request to finish
/// - Send any auth token found in headers back to token storage
/// - Wait for hyper request body, collecting it into a single chunk
/// - Parse JSON body as the given `EndpointType`, and return result/error.
///
/// All errors returned will have the given `Url` contained as part of the context.
///
/// # Parameters
///
/// - `token_storage`: token storage to store any tokens that were refreshed.
/// - `used_token`: token that was used when sending this request, if any.
///   if the server doesn't return a new token, and this is Some, the inner
///   token will be returned to the token storage.
/// - `url`: url that is being queried, used only for error and warning messages.
/// - `response`: actual hyper response that we're interpreting
pub fn interpret<T, R>(token_storage: T,
                       used_token: Option<Token>,
                       url: Url,
                       response: hyper::client::FutureResponse)
                       -> FutureResponse<R>
    where T: TokenStorage,
          R: EndpointType
{
    FutureResponse(Box::new(response.then(move |result| {
            let new_result = match result {
                Ok(v) => Ok((token_storage, used_token, url, v)),
                Err(e) => Err(Error::with_url(e, Some(url))),
            };

            new_result
        })
        .and_then(|(token_storage, used_token, url, mut response)| {
            if !response.status().is_success() {
                return Err(Error::with_url(response.status(), Some(url.clone())));
            }

            let token_to_return = {
                header! { (TokenHeader, "X-Token") => [String] }

                let new_token = response.headers_mut().remove::<TokenHeader>().map(|h| h.0);

                match new_token {
                    Some(token) => {
                        if token.is_empty() {
                            Some(token)
                        } else {
                            used_token
                        }
                    }
                    None => used_token,
                }
            };

            if let Some(token) = token_to_return {
                token_storage.return_token(token);
            }

            Ok((url, response))
        })
        .and_then(|(url, response)| {
            response.body().concat2().then(move |result| match result {
                Ok(v) => Ok((url, v)),
                Err(e) => Err(Error::with_url(e, Some(url))),
            })
        })
        .and_then(|(url, data): (_, hyper::Chunk)| {
            let parsed = match serde_json::from_slice(&data) {
                Ok(json) => deserialize_with_warnings::<R>(&json, &url)?,
                Err(e) => return Err(Error::with_url(e, Some(url))),
            };

            R::from_raw(parsed)
        })))
}

fn deserialize_with_warnings<T: EndpointType>(input: &serde_json::Value, url: &Url) -> Result<T::RequestResult, Error> {
    let mut unused = Vec::new();

    let res = match serde_ignored::deserialize::<_, _, T::RequestResult>(input, |path| unused.push(path.to_string())) {
        Ok(v) => Ok(v),
        Err(e1) => {
            unused.clear();
            match serde_ignored::deserialize::<_, _, T::ErrorResult>(input, |path| unused.push(path.to_string())) {
                Ok(v) => Err(Error::with_json(v, Some(url.clone()), Some(input.clone()))),
                // Favor the primary parsing error if one occurs parsing the error type as well.
                Err(_) => Err(Error::with_json(e1, Some(url.clone()), Some(input.clone()))),
            }
        }
    };

    if !unused.is_empty() {
        warn!("screeps API lib didn't parse some data retrieved from: {}\n\
               full data: {}\n\
               unparsed fields: {:?}",
              url,
              serde_json::to_string(input).unwrap(),
              unused);
    }

    res
}
<commit_msg>Include JSON response body in status code errors<commit_after>//! Semi-internal functionality related to networking.
use std::fmt;

use {hyper, serde_json, serde_ignored};

use futures::{Poll, Future, Stream};
use url::Url;

use {Token, TokenStorage, EndpointType, Error};

/// Struct mirroring `hyper`'s FutureResponse, but with parsing that happens after the request is finished.
#[must_use = "futures do nothing unless polled"]
pub struct FutureResponse<R: EndpointType>(Box<Future<Item = R, Error = Error>>);

impl<R: EndpointType> fmt::Debug for FutureResponse<R> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ScreepsFutureResponse")
            .field("inner", &"<boxed future>")
            .finish()
    }
}

impl<R> Future for FutureResponse<R>
    where R: EndpointType
{
    type Item = R;
    type Error = Error;

    fn poll(&mut self) -> Poll<R, Error> {
        self.0.poll()
    }
}

/// Interpret a hyper result as the result from a specific endpoint.
///
/// The returned future will:
///
/// - Wait for the hyper request to finish
/// - Send any auth token found in headers back to token storage
/// - Wait for hyper request body, collecting it into a single chunk
/// - Parse JSON body as the given `EndpointType`, and return result/error.
///
/// All errors returned will have the given `Url` contained as part of the context.
///
/// # Parameters
///
/// - `token_storage`: token storage to store any tokens that were refreshed.
/// - `used_token`: token that was used when sending this request, if any.
///   if the server doesn't return a new token, and this is Some, the inner
///   token will be returned to the token storage.
/// - `url`: url that is being queried, used only for error and warning messages.
/// - `response`: actual hyper response that we're interpreting
pub fn interpret<T, R>(token_storage: T,
                       used_token: Option<Token>,
                       url: Url,
                       response: hyper::client::FutureResponse)
                       -> FutureResponse<R>
    where T: TokenStorage,
          R: EndpointType
{
    FutureResponse(Box::new(response.then(move |result| {
            let new_result = match result {
                Ok(v) => Ok((token_storage, used_token, url, v)),
                Err(e) => Err(Error::with_url(e, Some(url))),
            };

            new_result
        })
        .and_then(|(token_storage, used_token, url, mut response)| {
            let token_to_return = {
                header! { (TokenHeader, "X-Token") => [String] }

                let new_token = response.headers_mut().remove::<TokenHeader>().map(|h| h.0);

                match new_token {
                    Some(token) => {
                        if token.is_empty() {
                            Some(token)
                        } else {
                            used_token
                        }
                    }
                    None => used_token,
                }
            };

            if let Some(token) = token_to_return {
                token_storage.return_token(token);
            }

            Ok((url, response))
        })
        .and_then(|(url, response)| {
            let status = response.status();

            response.body().concat2().then(move |result| match result {
                Ok(v) => Ok((status, url, v)),
                Err(e) => Err(Error::with_url(e, Some(url))),
            })
        })
        .and_then(|(status, url, data): (hyper::status::StatusCode, _, hyper::Chunk)| {
            let json_result = serde_json::from_slice(&data);

            // insert this check here so we can include response body in status errors.
            if !status.is_success() {
                if let Ok(json) = json_result {
                    return Err(Error::with_json(status, Some(url), Some(json)));
                } else {
                    return Err(Error::with_url(status, Some(url)));
                }
            }

            let parsed = match json_result {
                Ok(json) => deserialize_with_warnings::<R>(&json, &url)?,
                Err(e) => return Err(Error::with_url(e, Some(url))),
            };

            R::from_raw(parsed)
        })))
}

fn deserialize_with_warnings<T: EndpointType>(input: &serde_json::Value, url: &Url) -> Result<T::RequestResult, Error> {
    let mut unused = Vec::new();

    let res = match serde_ignored::deserialize::<_, _, T::RequestResult>(input, |path| unused.push(path.to_string())) {
        Ok(v) => Ok(v),
        Err(e1) => {
            unused.clear();
            match serde_ignored::deserialize::<_, _, T::ErrorResult>(input, |path| unused.push(path.to_string())) {
                Ok(v) => Err(Error::with_json(v, Some(url.clone()), Some(input.clone()))),
                // Favor the primary parsing error if one occurs parsing the error type as well.
                Err(_) => Err(Error::with_json(e1, Some(url.clone()), Some(input.clone()))),
            }
        }
    };

    if !unused.is_empty() {
        warn!("screeps API lib didn't parse some data retrieved from: {}\n\
               full data: {}\n\
               unparsed fields: {:?}",
              url,
              serde_json::to_string(input).unwrap(),
              unused);
    }

    res
}
<|endoftext|>


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

use std::borrow::{Borrow, Cow};
use std::cmp;
use std::fmt;
use std::hash;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use std::slice;
use std::str;
use std::usize;

/// A string that is either shared (heap-allocated and reference-counted) or borrowed.
///
/// Equivalent to `enum { Borrowed(&'a str), Shared(Rc<String>) }`, but stored more compactly.
///
/// FIXME(https://github.com/rust-lang/rfcs/issues/1230): use an actual enum if/when
/// the compiler can do this layout optimization.
pub struct CowRcStr<'a> {
    /// FIXME: https://github.com/rust-lang/rust/issues/27730 use NonZero or Shared.
    /// In the meantime we abuse `&'static _` to get the effect of `NonZero<*const _>`.
    /// `ptr` doesn’t really have the 'static lifetime!
    ptr: &'static (),

    /// * If `borrowed_len_or_max == usize::MAX`, then `ptr` represents `NonZero<*const String>`
    ///   from `Rc::into_raw`.
    ///   The lifetime parameter `'a` is irrelevant in this case.
    ///
    /// * Otherwise, `ptr` represents the `NonZero<*const u8>` data component of `&'a str`,
    ///   and `borrowed_len_or_max` its length.
    borrowed_len_or_max: usize,

    phantom: PhantomData<Result<&'a str, Rc<String>>>,
}

fn _static_assert_same_size<'a>() {
    // "Instantiate" the generic function without calling it.
    let _ = mem::transmute::<CowRcStr<'a>, Option<CowRcStr<'a>>>;
}

impl<'a> From<Cow<'a, str>> for CowRcStr<'a> {
    #[inline]
    fn from(s: Cow<'a, str>) -> Self {
        match s {
            Cow::Borrowed(s) => CowRcStr::from(s),
            Cow::Owned(s) => CowRcStr::from(s),
        }
    }
}

impl<'a> From<&'a str> for CowRcStr<'a> {
    #[inline]
    fn from(s: &'a str) -> Self {
        let len = s.len();
        assert!(len < usize::MAX);
        CowRcStr {
            ptr: unsafe { &*(s.as_ptr() as *const ()) },
            borrowed_len_or_max: len,
            phantom: PhantomData,
        }
    }
}

impl<'a> From<String> for CowRcStr<'a> {
    #[inline]
    fn from(s: String) -> Self {
        CowRcStr::from_rc(Rc::new(s))
    }
}

impl<'a> CowRcStr<'a> {
    #[inline]
    fn from_rc(s: Rc<String>) -> Self {
        let ptr = unsafe { &*(Rc::into_raw(s) as *const ()) };
        CowRcStr {
            ptr: ptr,
            borrowed_len_or_max: usize::MAX,
            phantom: PhantomData,
        }
    }

    #[inline]
    fn unpack(&self) -> Result<&'a str, *const String> {
        if self.borrowed_len_or_max == usize::MAX {
            Err(self.ptr as *const () as *const String)
        } else {
            unsafe {
                Ok(str::from_utf8_unchecked(slice::from_raw_parts(
                    self.ptr as *const () as *const u8,
                    self.borrowed_len_or_max,
                )))
            }
        }
    }

    /// Convert into `String`, re-using an existing memory allocation if possible.
    #[inline]
    pub fn into_owned(self) -> String {
        let unpacked = self.unpack();

        // Inhibit destructor: we’re taking ownership of this strong reference (if any)
        mem::forget(self);

        match unpacked {
            Ok(s) => s.to_owned(),
            Err(ptr) => {
                let rc = unsafe {
                    Rc::from_raw(ptr)
                };
                Rc::try_unwrap(rc).unwrap_or_else(|rc| (*rc).clone())
            }
        }
    }
}

impl<'a> Clone for CowRcStr<'a> {
    #[inline]
    fn clone(&self) -> Self {
        match self.unpack() {
            Err(ptr) => {
                let rc = unsafe {
                    Rc::from_raw(ptr)
                };
                let new_rc = rc.clone();
                mem::forget(rc);  // Don’t actually take ownership of this strong reference
                CowRcStr::from_rc(new_rc)
            }
            Ok(_) => {
                CowRcStr { ..*self }
            }
        }
    }
}

impl<'a> Drop for CowRcStr<'a> {
    #[inline]
    fn drop(&mut self) {
        if let Err(ptr) = self.unpack() {
            mem::drop(unsafe {
                Rc::from_raw(ptr)
            })
        }
    }
}

impl<'a> Deref for CowRcStr<'a> {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        self.unpack().unwrap_or_else(|ptr| unsafe {
            &**ptr
        })
    }
}

// Boilerplate / trivial impls below.

impl<'a> AsRef<str> for CowRcStr<'a> {
    #[inline]
    fn as_ref(&self) -> &str {
        self
    }
}

impl<'a> Borrow<str> for CowRcStr<'a> {
    #[inline]
    fn borrow(&self) -> &str {
        self
    }
}

impl<'a> Default for CowRcStr<'a> {
    #[inline]
    fn default() -> Self {
        Self::from("")
    }
}

impl<'a> hash::Hash for CowRcStr<'a> {
    #[inline]
    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
        str::hash(self, hasher)
    }
}

impl<'a, T: AsRef<str>> PartialEq<T> for CowRcStr<'a> {
    #[inline]
    fn eq(&self, other: &T) -> bool {
        str::eq(self, other.as_ref())
    }
}

impl<'a, T: AsRef<str>> PartialOrd<T> for CowRcStr<'a> {
    #[inline]
    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
        str::partial_cmp(self, other.as_ref())
    }
}

impl<'a> Eq for CowRcStr<'a> {}

impl<'a> Ord for CowRcStr<'a> {
    #[inline]
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        str::cmp(self, other)
    }
}

impl<'a> fmt::Display for CowRcStr<'a> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        str::fmt(self, formatter)
    }
}

impl<'a> fmt::Debug for CowRcStr<'a> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        str::fmt(self, formatter)
    }
}
<commit_msg>Remove CowRcStr::into_owned<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::borrow::{Borrow, Cow};
use std::cmp;
use std::fmt;
use std::hash;
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::rc::Rc;
use std::slice;
use std::str;
use std::usize;

/// A string that is either shared (heap-allocated and reference-counted) or borrowed.
///
/// Equivalent to `enum { Borrowed(&'a str), Shared(Rc<String>) }`, but stored more compactly.
///
/// FIXME(https://github.com/rust-lang/rfcs/issues/1230): use an actual enum if/when
/// the compiler can do this layout optimization.
pub struct CowRcStr<'a> {
    /// FIXME: https://github.com/rust-lang/rust/issues/27730 use NonZero or Shared.
    /// In the meantime we abuse `&'static _` to get the effect of `NonZero<*const _>`.
    /// `ptr` doesn’t really have the 'static lifetime!
    ptr: &'static (),

    /// * If `borrowed_len_or_max == usize::MAX`, then `ptr` represents `NonZero<*const String>`
    ///   from `Rc::into_raw`.
    ///   The lifetime parameter `'a` is irrelevant in this case.
    ///
    /// * Otherwise, `ptr` represents the `NonZero<*const u8>` data component of `&'a str`,
    ///   and `borrowed_len_or_max` its length.
    borrowed_len_or_max: usize,

    phantom: PhantomData<Result<&'a str, Rc<String>>>,
}

fn _static_assert_same_size<'a>() {
    // "Instantiate" the generic function without calling it.
    let _ = mem::transmute::<CowRcStr<'a>, Option<CowRcStr<'a>>>;
}

impl<'a> From<Cow<'a, str>> for CowRcStr<'a> {
    #[inline]
    fn from(s: Cow<'a, str>) -> Self {
        match s {
            Cow::Borrowed(s) => CowRcStr::from(s),
            Cow::Owned(s) => CowRcStr::from(s),
        }
    }
}

impl<'a> From<&'a str> for CowRcStr<'a> {
    #[inline]
    fn from(s: &'a str) -> Self {
        let len = s.len();
        assert!(len < usize::MAX);
        CowRcStr {
            ptr: unsafe { &*(s.as_ptr() as *const ()) },
            borrowed_len_or_max: len,
            phantom: PhantomData,
        }
    }
}

impl<'a> From<String> for CowRcStr<'a> {
    #[inline]
    fn from(s: String) -> Self {
        CowRcStr::from_rc(Rc::new(s))
    }
}

impl<'a> CowRcStr<'a> {
    #[inline]
    fn from_rc(s: Rc<String>) -> Self {
        let ptr = unsafe { &*(Rc::into_raw(s) as *const ()) };
        CowRcStr {
            ptr: ptr,
            borrowed_len_or_max: usize::MAX,
            phantom: PhantomData,
        }
    }

    #[inline]
    fn unpack(&self) -> Result<&'a str, *const String> {
        if self.borrowed_len_or_max == usize::MAX {
            Err(self.ptr as *const () as *const String)
        } else {
            unsafe {
                Ok(str::from_utf8_unchecked(slice::from_raw_parts(
                    self.ptr as *const () as *const u8,
                    self.borrowed_len_or_max,
                )))
            }
        }
    }
}

impl<'a> Clone for CowRcStr<'a> {
    #[inline]
    fn clone(&self) -> Self {
        match self.unpack() {
            Err(ptr) => {
                let rc = unsafe {
                    Rc::from_raw(ptr)
                };
                let new_rc = rc.clone();
                mem::forget(rc);  // Don’t actually take ownership of this strong reference
                CowRcStr::from_rc(new_rc)
            }
            Ok(_) => {
                CowRcStr { ..*self }
            }
        }
    }
}

impl<'a> Drop for CowRcStr<'a> {
    #[inline]
    fn drop(&mut self) {
        if let Err(ptr) = self.unpack() {
            mem::drop(unsafe {
                Rc::from_raw(ptr)
            })
        }
    }
}

impl<'a> Deref for CowRcStr<'a> {
    type Target = str;

    #[inline]
    fn deref(&self) -> &str {
        self.unpack().unwrap_or_else(|ptr| unsafe {
            &**ptr
        })
    }
}

// Boilerplate / trivial impls below.

impl<'a> AsRef<str> for CowRcStr<'a> {
    #[inline]
    fn as_ref(&self) -> &str {
        self
    }
}

impl<'a> Borrow<str> for CowRcStr<'a> {
    #[inline]
    fn borrow(&self) -> &str {
        self
    }
}

impl<'a> Default for CowRcStr<'a> {
    #[inline]
    fn default() -> Self {
        Self::from("")
    }
}

impl<'a> hash::Hash for CowRcStr<'a> {
    #[inline]
    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
        str::hash(self, hasher)
    }
}

impl<'a, T: AsRef<str>> PartialEq<T> for CowRcStr<'a> {
    #[inline]
    fn eq(&self, other: &T) -> bool {
        str::eq(self, other.as_ref())
    }
}

impl<'a, T: AsRef<str>> PartialOrd<T> for CowRcStr<'a> {
    #[inline]
    fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
        str::partial_cmp(self, other.as_ref())
    }
}

impl<'a> Eq for CowRcStr<'a> {}

impl<'a> Ord for CowRcStr<'a> {
    #[inline]
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        str::cmp(self, other)
    }
}

impl<'a> fmt::Display for CowRcStr<'a> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        str::fmt(self, formatter)
    }
}

impl<'a> fmt::Debug for CowRcStr<'a> {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        str::fmt(self, formatter)
    }
}
<|endoftext|>


<commit_before>//! Tests for containers.rs

#[cfg(test)]
mod tests {
    use rustwlc::handle::{WlcView, WlcOutput};
    use std::rc::*;
    use super::super::containers::{Container, ContainerType, Layout, Node};

    #[test]
    fn it_works() {
        let mut result = vec!();
        for _ in 1..10 {
            result.push(Container::new_root());
        }
        for thing in result {
            drop(thing);
        }
        //assert_eq!(result[
    }
}
<commit_msg>Added tests for root, including one that currently fails (tests if you can only make one root, haven't implemented a mechanism for that yet<commit_after>//! Tests for containers.rs

#[cfg(test)]
mod tests {
    use rustwlc::handle::{WlcView, WlcOutput};
    use std::rc::*;
    use super::super::containers::{Container, ContainerType, Layout, Node};

    #[test]
    #[should_panic(expected = "Can only be one root")]
    /// Test to make sure that there can be only one root node
    fn test_one_root() {
        let root = Container::new_root();
        // Should panic
        let root2 = Container::new_root();
    }

    #[test]
    /// Verify that root node has required properties
    fn root_validity() {
        let root = Rc::new(Container::new_root());
        // Make sure it starts with no children
        // This will change when we add Workspaces when we make the root
        assert!(root.get_children().is_none());
        // This is the tippity-top of the tree
        assert!(root.get_parent().is_none());
        assert_eq!(root.get_type(), ContainerType::Root);
        // Should this be true? It makes sense, but it might cause complications
        // so we'll go with false for now
        assert!(! root.is_focused());
        // Root is parent of all nodes, including itself
        assert!(root.is_parent_of(root.clone()));
        // Root is not a child of anything, including itself
        // NOTE Add more test when we have more container types
        assert!(! root.is_child_of(root.clone()));
        assert!(root.is_root());
    }

    #[test]
    #[should_panic(expected = "Cannot remove the root of the tree")]
    /// Ensures you cannot remove the root node
    fn remove_root_test() {
        let root = Container::new_root();
        root.remove_container();
    }

    #[test]
    #[should_panic(expected = "Root has no dimensions")]
    fn get_root_dimensions_test() {
        let root = Container::new_root();
        root.get_dimensions();
    }

    #[test]
    #[should_panic(expected = "Root has no position")]
    fn get_root_position_test() {
        let root = Container::new_root();
        root.get_position();
    }
}
<|endoftext|>