<commit_before>use futures_01::executor::{
    spawn as spawn01, Notify as Notify01, NotifyHandle as NotifyHandle01,
    Spawn as Spawn01, UnsafeNotify as UnsafeNotify01,
};
use futures_01::{
    Async as Async01, AsyncSink as AsyncSink01, Future as Future01,
    Sink as Sink01, Stream as Stream01,
};
use futures_core::{task as task03, Future as Future03, Stream as Stream03};
use std::pin::Pin;
use std::task::Waker;
use futures_sink::Sink as Sink03;

/// Converts a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
/// object to a futures 0.3-compatible version,
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat01As03<T> {
    pub(crate) inner: Spawn01<T>,
}

impl<T> Unpin for Compat01As03<T> {}

impl<T> Compat01As03<T> {
    /// Wraps a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
    /// object in a futures 0.3-compatible wrapper.
    pub fn new(object: T) -> Compat01As03<T> {
        Compat01As03 {
            inner: spawn01(object),
        }
    }

    fn in_notify<R>(&mut self, waker: &Waker, f: impl FnOnce(&mut T) -> R) -> R {
        let notify = &WakerToHandle(waker);
        self.inner.poll_fn_notify(notify, 0, f)
    }
}

/// Extension trait for futures 0.1 [`Future`](futures::future::Future)
pub trait Future01CompatExt: Future01 {
    /// Converts a futures 0.1
    /// [`Future<Item = T, Error = E>`](futures::future::Future)
    /// into a futures 0.3
    /// [`Future<Output = Result<T, E>>`](futures_core::future::Future).
    fn compat(self) -> Compat01As03<Self>
    where
        Self: Sized,
    {
        Compat01As03::new(self)
    }
}
impl<Fut: Future01> Future01CompatExt for Fut {}

/// Extension trait for futures 0.1 [`Stream`](futures::stream::Stream)
pub trait Stream01CompatExt: Stream01 {
    /// Converts a futures 0.1
    /// [`Stream<Item = T, Error = E>`](futures::stream::Stream)
    /// into a futures 0.3
    /// [`Stream<Item = Result<T, E>>`](futures_core::stream::Stream).
    fn compat(self) -> Compat01As03<Self>
    where
        Self: Sized,
    {
        Compat01As03::new(self)
    }
}
impl<St: Stream01> Stream01CompatExt for St {}

/// Extension trait for futures 0.1 [`Sink`](futures::sink::Sink)
pub trait Sink01CompatExt: Sink01 {
    /// Converts a futures 0.1
    /// [`Sink<SinkItem = T, SinkError = E>`](futures::sink::Sink)
    /// into a futures 0.3
    /// [`Sink<SinkItem = T, SinkError = E>`](futures_sink::sink::Sink).
    fn compat_sink(self) -> Compat01As03Sink<Self, Self::SinkItem>
    where
        Self: Sized,
    {
        Compat01As03Sink::new(self)
    }
}
impl<Si: Sink01> Sink01CompatExt for Si {}

fn poll_01_to_03<T, E>(x: Result<Async01<T>, E>) -> task03::Poll<Result<T, E>> {
    match x {
        Ok(Async01::Ready(t)) => task03::Poll::Ready(Ok(t)),
        Ok(Async01::NotReady) => task03::Poll::Pending,
        Err(e) => task03::Poll::Ready(Err(e)),
    }
}

impl<Fut: Future01> Future03 for Compat01As03<Fut> {
    type Output = Result<Fut::Item, Fut::Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        waker: &Waker,
    ) -> task03::Poll<Self::Output> {
        poll_01_to_03(self.in_notify(waker, Future01::poll))
    }
}

impl<St: Stream01> Stream03 for Compat01As03<St> {
    type Item = Result<St::Item, St::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        waker: &Waker,
    ) -> task03::Poll<Option<Self::Item>> {
        match self.in_notify(waker, Stream01::poll) {
            Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
            Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
            Ok(Async01::NotReady) => task03::Poll::Pending,
            Err(e) => task03::Poll::Ready(Some(Err(e))),
        }
    }
}

/// Converts a futures 0.1 Sink object to a futures 0.3-compatible version
#[derive(Debug)]
#[must_use = "sinks do nothing unless polled"]
pub struct Compat01As03Sink<S, SinkItem> {
    pub(crate) inner: Spawn01<S>,
    pub(crate) buffer: Option<SinkItem>,
    pub(crate) close_started: bool,
}

impl<S, SinkItem> Unpin for Compat01As03Sink<S, SinkItem> {}

impl<S, SinkItem> Compat01As03Sink<S, SinkItem> {
    /// Wraps a futures 0.1 Sink object in a futures 0.3-compatible wrapper.
    pub fn new(inner: S) -> Compat01As03Sink<S, SinkItem> {
        Compat01As03Sink {
            inner: spawn01(inner),
            buffer: None,
            close_started: false
        }
    }

    fn in_notify<R>(
        &mut self,
        lw: &LocalWaker,
        f: impl FnOnce(&mut S) -> R,
    ) -> R {
        let notify = &WakerToHandle(lw.as_waker());
        self.inner.poll_fn_notify(notify, 0, f)
    }
}

impl<S, SinkItem> Stream03 for Compat01As03Sink<S, SinkItem>
where
    S: Stream01,
{
    type Item = Result<S::Item, S::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Option<Self::Item>> {
        match self.in_notify(lw, |f| f.poll()) {
            Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
            Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
            Ok(Async01::NotReady) => task03::Poll::Pending,
            Err(e) => task03::Poll::Ready(Some(Err(e))),
        }
    }
}

impl<S, SinkItem> Sink03 for Compat01As03Sink<S, SinkItem>
where
    S: Sink01<SinkItem = SinkItem>,
{
    type SinkItem = SinkItem;
    type SinkError = S::SinkError;

    fn start_send(
        mut self: Pin<&mut Self>,
        item: Self::SinkItem,
    ) -> Result<(), Self::SinkError> {
        debug_assert!(self.buffer.is_none());
        self.buffer = Some(item);
        Ok(())
    }

    fn poll_ready(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Result<(), Self::SinkError>> {
        match self.buffer.take() {
            Some(item) => match self.in_notify(lw, |f| f.start_send(item)) {
                Ok(AsyncSink01::Ready) => task03::Poll::Ready(Ok(())),
                Ok(AsyncSink01::NotReady(i)) => {
                    self.buffer = Some(i);
                    task03::Poll::Pending
                }
                Err(e) => task03::Poll::Ready(Err(e)),
            },
            None => task03::Poll::Ready(Ok(())),
        }
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Result<(), Self::SinkError>> {
        let item = self.buffer.take();
        match self.in_notify(lw, |f| match item {
            Some(i) => match f.start_send(i) {
                Ok(AsyncSink01::Ready) => f.poll_complete().map(|i| (i, None)),
                Ok(AsyncSink01::NotReady(t)) => {
                    Ok((Async01::NotReady, Some(t)))
                }
                Err(e) => Err(e),
            },
            None => f.poll_complete().map(|i| (i, None)),
        }) {
            Ok((Async01::Ready(_), _)) => task03::Poll::Ready(Ok(())),
            Ok((Async01::NotReady, item)) => {
                self.buffer = item;
                task03::Poll::Pending
            }
            Err(e) => task03::Poll::Ready(Err(e)),
        }
    }

    fn poll_close(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Result<(), Self::SinkError>> {
        let item = self.buffer.take();
        let close_started = self.close_started;

        let result = self.in_notify(lw, |f| {
            if !close_started {
                if let Some(item) = item {
                    if let AsyncSink01::NotReady(item) = f.start_send(item)? {
                        return Ok((Async01::NotReady, Some(item), false));
                    }
                }

                if let Async01::NotReady = f.poll_complete()? {
                    return Ok((Async01::NotReady, None, false));
                }
            }

            Ok((<S as Sink01>::close(f)?, None, true))
        });

        match result {
            Ok((Async01::Ready(_), _, _)) => task03::Poll::Ready(Ok(())),
            Ok((Async01::NotReady, item, close_started)) => {
                self.buffer = item;
                self.close_started = close_started;
                task03::Poll::Pending
            }
            Err(e) => task03::Poll::Ready(Err(e)),
        }
    }
}

struct NotifyWaker(task03::Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl<'a> From<WakerToHandle<'a>> for NotifyHandle01 {
    fn from(handle: WakerToHandle<'a>) -> NotifyHandle01 {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle01::new(Box::into_raw(ptr)) }
    }
}

impl Notify01 for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake();
    }
}

unsafe impl UnsafeNotify01 for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle01 {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify01 = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify01));
    }
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{
        AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03, Initializer,
    };
    use std::io::Error;
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    impl<R: AsyncRead01> AsyncRead03 for Compat01As03<R> {
        unsafe fn initializer(&self) -> Initializer {
            // check if `prepare_uninitialized_buffer` needs zeroing
            if self.inner.get_ref().prepare_uninitialized_buffer(&mut [1]) {
                Initializer::zeroing()
            } else {
                Initializer::nop()
            }
        }

        fn poll_read(&mut self, waker: &task03::Waker, buf: &mut [u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(waker, |x| x.poll_read(buf)))
        }
    }

    impl<W: AsyncWrite01> AsyncWrite03 for Compat01As03<W> {
        fn poll_write(&mut self, waker: &task03::Waker, buf: &[u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(waker, |x| x.poll_write(buf)))
        }

        fn poll_flush(&mut self, waker: &task03::Waker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(waker, AsyncWrite01::poll_flush))
        }

        fn poll_close(&mut self, waker: &task03::Waker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(waker, AsyncWrite01::shutdown))
        }
    }
}
<commit_msg>Rename compat_sink to sink_compat<commit_after>use futures_01::executor::{
    spawn as spawn01, Notify as Notify01, NotifyHandle as NotifyHandle01,
    Spawn as Spawn01, UnsafeNotify as UnsafeNotify01,
};
use futures_01::{
    Async as Async01, AsyncSink as AsyncSink01, Future as Future01,
    Sink as Sink01, Stream as Stream01,
};
use futures_core::{task as task03, Future as Future03, Stream as Stream03};
use std::pin::Pin;
use std::task::Waker;
use futures_sink::Sink as Sink03;

/// Converts a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
/// object to a futures 0.3-compatible version,
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct Compat01As03<T> {
    pub(crate) inner: Spawn01<T>,
}

impl<T> Unpin for Compat01As03<T> {}

impl<T> Compat01As03<T> {
    /// Wraps a futures 0.1 Future, Stream, AsyncRead, or AsyncWrite
    /// object in a futures 0.3-compatible wrapper.
    pub fn new(object: T) -> Compat01As03<T> {
        Compat01As03 {
            inner: spawn01(object),
        }
    }

    fn in_notify<R>(&mut self, waker: &Waker, f: impl FnOnce(&mut T) -> R) -> R {
        let notify = &WakerToHandle(waker);
        self.inner.poll_fn_notify(notify, 0, f)
    }
}

/// Extension trait for futures 0.1 [`Future`](futures::future::Future)
pub trait Future01CompatExt: Future01 {
    /// Converts a futures 0.1
    /// [`Future<Item = T, Error = E>`](futures::future::Future)
    /// into a futures 0.3
    /// [`Future<Output = Result<T, E>>`](futures_core::future::Future).
    fn compat(self) -> Compat01As03<Self>
    where
        Self: Sized,
    {
        Compat01As03::new(self)
    }
}
impl<Fut: Future01> Future01CompatExt for Fut {}

/// Extension trait for futures 0.1 [`Stream`](futures::stream::Stream)
pub trait Stream01CompatExt: Stream01 {
    /// Converts a futures 0.1
    /// [`Stream<Item = T, Error = E>`](futures::stream::Stream)
    /// into a futures 0.3
    /// [`Stream<Item = Result<T, E>>`](futures_core::stream::Stream).
    fn compat(self) -> Compat01As03<Self>
    where
        Self: Sized,
    {
        Compat01As03::new(self)
    }
}
impl<St: Stream01> Stream01CompatExt for St {}

/// Extension trait for futures 0.1 [`Sink`](futures::sink::Sink)
pub trait Sink01CompatExt: Sink01 {
    /// Converts a futures 0.1
    /// [`Sink<SinkItem = T, SinkError = E>`](futures::sink::Sink)
    /// into a futures 0.3
    /// [`Sink<SinkItem = T, SinkError = E>`](futures_sink::sink::Sink).
    fn sink_compat(self) -> Compat01As03Sink<Self, Self::SinkItem>
    where
        Self: Sized,
    {
        Compat01As03Sink::new(self)
    }
}
impl<Si: Sink01> Sink01CompatExt for Si {}

fn poll_01_to_03<T, E>(x: Result<Async01<T>, E>) -> task03::Poll<Result<T, E>> {
    match x {
        Ok(Async01::Ready(t)) => task03::Poll::Ready(Ok(t)),
        Ok(Async01::NotReady) => task03::Poll::Pending,
        Err(e) => task03::Poll::Ready(Err(e)),
    }
}

impl<Fut: Future01> Future03 for Compat01As03<Fut> {
    type Output = Result<Fut::Item, Fut::Error>;

    fn poll(
        mut self: Pin<&mut Self>,
        waker: &Waker,
    ) -> task03::Poll<Self::Output> {
        poll_01_to_03(self.in_notify(waker, Future01::poll))
    }
}

impl<St: Stream01> Stream03 for Compat01As03<St> {
    type Item = Result<St::Item, St::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        waker: &Waker,
    ) -> task03::Poll<Option<Self::Item>> {
        match self.in_notify(waker, Stream01::poll) {
            Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
            Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
            Ok(Async01::NotReady) => task03::Poll::Pending,
            Err(e) => task03::Poll::Ready(Some(Err(e))),
        }
    }
}

/// Converts a futures 0.1 Sink object to a futures 0.3-compatible version
#[derive(Debug)]
#[must_use = "sinks do nothing unless polled"]
pub struct Compat01As03Sink<S, SinkItem> {
    pub(crate) inner: Spawn01<S>,
    pub(crate) buffer: Option<SinkItem>,
    pub(crate) close_started: bool,
}

impl<S, SinkItem> Unpin for Compat01As03Sink<S, SinkItem> {}

impl<S, SinkItem> Compat01As03Sink<S, SinkItem> {
    /// Wraps a futures 0.1 Sink object in a futures 0.3-compatible wrapper.
    pub fn new(inner: S) -> Compat01As03Sink<S, SinkItem> {
        Compat01As03Sink {
            inner: spawn01(inner),
            buffer: None,
            close_started: false
        }
    }

    fn in_notify<R>(
        &mut self,
        lw: &LocalWaker,
        f: impl FnOnce(&mut S) -> R,
    ) -> R {
        let notify = &WakerToHandle(lw.as_waker());
        self.inner.poll_fn_notify(notify, 0, f)
    }
}

impl<S, SinkItem> Stream03 for Compat01As03Sink<S, SinkItem>
where
    S: Stream01,
{
    type Item = Result<S::Item, S::Error>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Option<Self::Item>> {
        match self.in_notify(lw, |f| f.poll()) {
            Ok(Async01::Ready(Some(t))) => task03::Poll::Ready(Some(Ok(t))),
            Ok(Async01::Ready(None)) => task03::Poll::Ready(None),
            Ok(Async01::NotReady) => task03::Poll::Pending,
            Err(e) => task03::Poll::Ready(Some(Err(e))),
        }
    }
}

impl<S, SinkItem> Sink03 for Compat01As03Sink<S, SinkItem>
where
    S: Sink01<SinkItem = SinkItem>,
{
    type SinkItem = SinkItem;
    type SinkError = S::SinkError;

    fn start_send(
        mut self: Pin<&mut Self>,
        item: Self::SinkItem,
    ) -> Result<(), Self::SinkError> {
        debug_assert!(self.buffer.is_none());
        self.buffer = Some(item);
        Ok(())
    }

    fn poll_ready(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Result<(), Self::SinkError>> {
        match self.buffer.take() {
            Some(item) => match self.in_notify(lw, |f| f.start_send(item)) {
                Ok(AsyncSink01::Ready) => task03::Poll::Ready(Ok(())),
                Ok(AsyncSink01::NotReady(i)) => {
                    self.buffer = Some(i);
                    task03::Poll::Pending
                }
                Err(e) => task03::Poll::Ready(Err(e)),
            },
            None => task03::Poll::Ready(Ok(())),
        }
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Result<(), Self::SinkError>> {
        let item = self.buffer.take();
        match self.in_notify(lw, |f| match item {
            Some(i) => match f.start_send(i) {
                Ok(AsyncSink01::Ready) => f.poll_complete().map(|i| (i, None)),
                Ok(AsyncSink01::NotReady(t)) => {
                    Ok((Async01::NotReady, Some(t)))
                }
                Err(e) => Err(e),
            },
            None => f.poll_complete().map(|i| (i, None)),
        }) {
            Ok((Async01::Ready(_), _)) => task03::Poll::Ready(Ok(())),
            Ok((Async01::NotReady, item)) => {
                self.buffer = item;
                task03::Poll::Pending
            }
            Err(e) => task03::Poll::Ready(Err(e)),
        }
    }

    fn poll_close(
        mut self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> task03::Poll<Result<(), Self::SinkError>> {
        let item = self.buffer.take();
        let close_started = self.close_started;

        let result = self.in_notify(lw, |f| {
            if !close_started {
                if let Some(item) = item {
                    if let AsyncSink01::NotReady(item) = f.start_send(item)? {
                        return Ok((Async01::NotReady, Some(item), false));
                    }
                }

                if let Async01::NotReady = f.poll_complete()? {
                    return Ok((Async01::NotReady, None, false));
                }
            }

            Ok((<S as Sink01>::close(f)?, None, true))
        });

        match result {
            Ok((Async01::Ready(_), _, _)) => task03::Poll::Ready(Ok(())),
            Ok((Async01::NotReady, item, close_started)) => {
                self.buffer = item;
                self.close_started = close_started;
                task03::Poll::Pending
            }
            Err(e) => task03::Poll::Ready(Err(e)),
        }
    }
}

struct NotifyWaker(task03::Waker);

#[derive(Clone)]
struct WakerToHandle<'a>(&'a task03::Waker);

impl<'a> From<WakerToHandle<'a>> for NotifyHandle01 {
    fn from(handle: WakerToHandle<'a>) -> NotifyHandle01 {
        let ptr = Box::new(NotifyWaker(handle.0.clone()));

        unsafe { NotifyHandle01::new(Box::into_raw(ptr)) }
    }
}

impl Notify01 for NotifyWaker {
    fn notify(&self, _: usize) {
        self.0.wake();
    }
}

unsafe impl UnsafeNotify01 for NotifyWaker {
    unsafe fn clone_raw(&self) -> NotifyHandle01 {
        WakerToHandle(&self.0).into()
    }

    unsafe fn drop_raw(&self) {
        let ptr: *const dyn UnsafeNotify01 = self;
        drop(Box::from_raw(ptr as *mut dyn UnsafeNotify01));
    }
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{
        AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03, Initializer,
    };
    use std::io::Error;
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    impl<R: AsyncRead01> AsyncRead03 for Compat01As03<R> {
        unsafe fn initializer(&self) -> Initializer {
            // check if `prepare_uninitialized_buffer` needs zeroing
            if self.inner.get_ref().prepare_uninitialized_buffer(&mut [1]) {
                Initializer::zeroing()
            } else {
                Initializer::nop()
            }
        }

        fn poll_read(&mut self, waker: &task03::Waker, buf: &mut [u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(waker, |x| x.poll_read(buf)))
        }
    }

    impl<W: AsyncWrite01> AsyncWrite03 for Compat01As03<W> {
        fn poll_write(&mut self, waker: &task03::Waker, buf: &[u8])
            -> task03::Poll<Result<usize, Error>>
        {
            poll_01_to_03(self.in_notify(waker, |x| x.poll_write(buf)))
        }

        fn poll_flush(&mut self, waker: &task03::Waker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(waker, AsyncWrite01::poll_flush))
        }

        fn poll_close(&mut self, waker: &task03::Waker)
            -> task03::Poll<Result<(), Error>>
        {
            poll_01_to_03(self.in_notify(waker, AsyncWrite01::shutdown))
        }
    }
}
<|endoftext|>


<commit_before>use futures_01::{
    task as task01, Async as Async01, AsyncSink as AsyncSink01,
    Future as Future01, Poll as Poll01, Sink as Sink01,
    StartSend as StartSend01, Stream as Stream01,
};
use futures_core::{
    task::{
        self as task03,
        RawWaker,
        RawWakerVTable,
    },
    TryFuture as TryFuture03,
    TryStream as TryStream03,
};
use futures_sink::Sink as Sink03;
use crate::task::{ArcWake as ArcWake03, WakerRef};
use std::{
    marker::PhantomData,
    mem,
    pin::Pin,
    sync::Arc,
    task::Context,
};

/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture),
/// [`TryStream`](futures_core::stream::TryStream) or
/// [`Sink`](futures_sink::Sink) into a futures 0.1
/// [`Future`](futures_01::future::Future),
/// [`Stream`](futures_01::stream::Stream) or
/// [`Sink`](futures_01::sink::Sink).
#[derive(Debug, Clone, Copy)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Compat<T> {
    pub(crate) inner: T,
}

/// Converts a futures 0.3 Sink object to a futures 0.1-compatible version
#[derive(Debug)]
#[must_use = "sinks do nothing unless polled"]
pub struct CompatSink<T, Item> {
    inner: T,
    _phantom: PhantomData<fn(Item)>,
}

impl<T> Compat<T> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`Compat`].
    ///
    /// For types which implement appropriate futures `0.3`
    /// traits, the result will be a type which implements
    /// the corresponding futures 0.1 type.
    pub fn new(inner: T) -> Compat<T> {
        Compat { inner }
    }
}

impl<T, Item> CompatSink<T, Item> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`CompatSink`].
    pub fn new(inner: T) -> Self {
        CompatSink {
            inner,
            _phantom: PhantomData,
        }
    }
}

fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>)
    -> Result<Async01<T>, E>
{
    match x? {
        task03::Poll::Ready(t) => Ok(Async01::Ready(t)),
        task03::Poll::Pending => Ok(Async01::NotReady),
    }
}

impl<Fut> Future01 for Compat<Fut>
where
    Fut: TryFuture03 + Unpin,
{
    type Item = Fut::Ok;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll01<Self::Item, Self::Error> {
        with_context(self, |inner, cx| poll_03_to_01(inner.try_poll(cx)))
    }
}

impl<St> Stream01 for Compat<St>
where
    St: TryStream03 + Unpin,
{
    type Item = St::Ok;
    type Error = St::Error;

    fn poll(&mut self) -> Poll01<Option<Self::Item>, Self::Error> {
        with_context(self, |inner, cx| match inner.try_poll_next(cx)? {
            task03::Poll::Ready(None) => Ok(Async01::Ready(None)),
            task03::Poll::Ready(Some(t)) => Ok(Async01::Ready(Some(t))),
            task03::Poll::Pending => Ok(Async01::NotReady),
        })
    }
}

impl<T, Item> Sink01 for CompatSink<T, Item>
where
    T: Sink03<Item> + Unpin,
{
    type SinkItem = Item;
    type SinkError = T::SinkError;

    fn start_send(
        &mut self,
        item: Self::SinkItem,
    ) -> StartSend01<Self::SinkItem, Self::SinkError> {
        with_sink_context(self, |mut inner, cx| {
            match inner.as_mut().poll_ready(cx)? {
                task03::Poll::Ready(()) => {
                    inner.start_send(item).map(|()| AsyncSink01::Ready)
                }
                task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)),
            }
        })
    }

    fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> {
        with_sink_context(self, |inner, cx| poll_03_to_01(inner.poll_flush(cx)))
    }

    fn close(&mut self) -> Poll01<(), Self::SinkError> {
        with_sink_context(self, |inner, cx| poll_03_to_01(inner.poll_close(cx)))
    }
}

#[derive(Clone)]
struct Current(task01::Task);

impl Current {
    fn new() -> Current {
        Current(task01::current())
    }

    fn as_waker(&self) -> WakerRef<'_> {
        unsafe fn ptr_to_current<'a>(ptr: *const ()) -> &'a Current {
            #[allow(clippy::cast_ptr_alignment)]
            &*(ptr as *const Current)
        }
        fn current_to_ptr(current: &Current) -> *const () {
            current as *const Current as *const ()
        }

        unsafe fn clone(ptr: *const ()) -> RawWaker {
            // Lazily create the `Arc` only when the waker is actually cloned.
            // FIXME: remove `transmute` when a `Waker` -> `RawWaker` conversion
            // function is landed in `core`.
            mem::transmute::<task03::Waker, RawWaker>(
                Arc::new(ptr_to_current(ptr).clone()).into_waker()
            )
        }
        unsafe fn drop(_: *const ()) {}
        unsafe fn wake(ptr: *const ()) {
            ptr_to_current(ptr).0.notify()
        }

        let ptr = current_to_ptr(self);
        let vtable = &RawWakerVTable::new(clone, wake, wake, drop);
        unsafe {
            WakerRef::new(task03::Waker::from_raw(RawWaker::new(ptr, vtable)))
        }
    }
}

impl ArcWake03 for Current {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}

fn with_context<T, R, F>(compat: &mut Compat<T>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> R,
{
    let current = Current::new();
    let waker = current.as_waker();
    let mut cx = Context::from_waker(&waker);
    f(Pin::new(&mut compat.inner), &mut cx)
}

fn with_sink_context<T, Item, R, F>(compat: &mut CompatSink<T, Item>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> R,
{
    let current = Current::new();
    let waker = current.as_waker();
    let mut cx = Context::from_waker(&waker);
    f(Pin::new(&mut compat.inner), &mut cx)
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>)
        -> Result<T, std::io::Error>
    {
        match x {
            task03::Poll::Ready(Ok(t)) => Ok(t),
            task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()),
            task03::Poll::Ready(Err(e)) => Err(e),
        }
    }

    impl<R: AsyncRead03 + Unpin> std::io::Read for Compat<R> {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_io(Pin::new(&mut self.inner).poll_read(&mut cx, buf))
        }
    }

    impl<R: AsyncRead03 + Unpin> AsyncRead01 for Compat<R> {
        unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
            let initializer = self.inner.initializer();
            let does_init = initializer.should_initialize();
            if does_init {
                initializer.initialize(buf);
            }
            does_init
        }
    }

    impl<W: AsyncWrite03 + Unpin> std::io::Write for Compat<W> {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_io(Pin::new(&mut self.inner).poll_write(&mut cx, buf))
        }

        fn flush(&mut self) -> std::io::Result<()> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_io(Pin::new(&mut self.inner).poll_flush(&mut cx))
        }
    }

    impl<W: AsyncWrite03 + Unpin> AsyncWrite01 for Compat<W> {
        fn shutdown(&mut self) -> std::io::Result<Async01<()>> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_01(Pin::new(&mut self.inner).poll_close(&mut cx))
        }
    }
}
<commit_msg>Add Compat::get_ref method<commit_after>use futures_01::{
    task as task01, Async as Async01, AsyncSink as AsyncSink01,
    Future as Future01, Poll as Poll01, Sink as Sink01,
    StartSend as StartSend01, Stream as Stream01,
};
use futures_core::{
    task::{
        self as task03,
        RawWaker,
        RawWakerVTable,
    },
    TryFuture as TryFuture03,
    TryStream as TryStream03,
};
use futures_sink::Sink as Sink03;
use crate::task::{ArcWake as ArcWake03, WakerRef};
use std::{
    marker::PhantomData,
    mem,
    pin::Pin,
    sync::Arc,
    task::Context,
};

/// Converts a futures 0.3 [`TryFuture`](futures_core::future::TryFuture),
/// [`TryStream`](futures_core::stream::TryStream) or
/// [`Sink`](futures_sink::Sink) into a futures 0.1
/// [`Future`](futures_01::future::Future),
/// [`Stream`](futures_01::stream::Stream) or
/// [`Sink`](futures_01::sink::Sink).
#[derive(Debug, Clone, Copy)]
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub struct Compat<T> {
    pub(crate) inner: T,
}

/// Converts a futures 0.3 Sink object to a futures 0.1-compatible version
#[derive(Debug)]
#[must_use = "sinks do nothing unless polled"]
pub struct CompatSink<T, Item> {
    inner: T,
    _phantom: PhantomData<fn(Item)>,
}

impl<T> Compat<T> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`Compat`].
    ///
    /// For types which implement appropriate futures `0.3`
    /// traits, the result will be a type which implements
    /// the corresponding futures 0.1 type.
    pub fn new(inner: T) -> Compat<T> {
        Compat { inner }
    }

    /// Get a reference to 0.3 Future, Stream, AsyncRead, or AsyncWrite object
    /// contained within.
    pub fn get_ref(&self) -> &T {
        &self.inner
    }
}

impl<T, Item> CompatSink<T, Item> {
    /// Returns the inner item.
    pub fn into_inner(self) -> T {
        self.inner
    }

    /// Creates a new [`CompatSink`].
    pub fn new(inner: T) -> Self {
        CompatSink {
            inner,
            _phantom: PhantomData,
        }
    }
}

fn poll_03_to_01<T, E>(x: task03::Poll<Result<T, E>>)
    -> Result<Async01<T>, E>
{
    match x? {
        task03::Poll::Ready(t) => Ok(Async01::Ready(t)),
        task03::Poll::Pending => Ok(Async01::NotReady),
    }
}

impl<Fut> Future01 for Compat<Fut>
where
    Fut: TryFuture03 + Unpin,
{
    type Item = Fut::Ok;
    type Error = Fut::Error;

    fn poll(&mut self) -> Poll01<Self::Item, Self::Error> {
        with_context(self, |inner, cx| poll_03_to_01(inner.try_poll(cx)))
    }
}

impl<St> Stream01 for Compat<St>
where
    St: TryStream03 + Unpin,
{
    type Item = St::Ok;
    type Error = St::Error;

    fn poll(&mut self) -> Poll01<Option<Self::Item>, Self::Error> {
        with_context(self, |inner, cx| match inner.try_poll_next(cx)? {
            task03::Poll::Ready(None) => Ok(Async01::Ready(None)),
            task03::Poll::Ready(Some(t)) => Ok(Async01::Ready(Some(t))),
            task03::Poll::Pending => Ok(Async01::NotReady),
        })
    }
}

impl<T, Item> Sink01 for CompatSink<T, Item>
where
    T: Sink03<Item> + Unpin,
{
    type SinkItem = Item;
    type SinkError = T::SinkError;

    fn start_send(
        &mut self,
        item: Self::SinkItem,
    ) -> StartSend01<Self::SinkItem, Self::SinkError> {
        with_sink_context(self, |mut inner, cx| {
            match inner.as_mut().poll_ready(cx)? {
                task03::Poll::Ready(()) => {
                    inner.start_send(item).map(|()| AsyncSink01::Ready)
                }
                task03::Poll::Pending => Ok(AsyncSink01::NotReady(item)),
            }
        })
    }

    fn poll_complete(&mut self) -> Poll01<(), Self::SinkError> {
        with_sink_context(self, |inner, cx| poll_03_to_01(inner.poll_flush(cx)))
    }

    fn close(&mut self) -> Poll01<(), Self::SinkError> {
        with_sink_context(self, |inner, cx| poll_03_to_01(inner.poll_close(cx)))
    }
}

#[derive(Clone)]
struct Current(task01::Task);

impl Current {
    fn new() -> Current {
        Current(task01::current())
    }

    fn as_waker(&self) -> WakerRef<'_> {
        unsafe fn ptr_to_current<'a>(ptr: *const ()) -> &'a Current {
            #[allow(clippy::cast_ptr_alignment)]
            &*(ptr as *const Current)
        }
        fn current_to_ptr(current: &Current) -> *const () {
            current as *const Current as *const ()
        }

        unsafe fn clone(ptr: *const ()) -> RawWaker {
            // Lazily create the `Arc` only when the waker is actually cloned.
            // FIXME: remove `transmute` when a `Waker` -> `RawWaker` conversion
            // function is landed in `core`.
            mem::transmute::<task03::Waker, RawWaker>(
                Arc::new(ptr_to_current(ptr).clone()).into_waker()
            )
        }
        unsafe fn drop(_: *const ()) {}
        unsafe fn wake(ptr: *const ()) {
            ptr_to_current(ptr).0.notify()
        }

        let ptr = current_to_ptr(self);
        let vtable = &RawWakerVTable::new(clone, wake, wake, drop);
        unsafe {
            WakerRef::new(task03::Waker::from_raw(RawWaker::new(ptr, vtable)))
        }
    }
}

impl ArcWake03 for Current {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        arc_self.0.notify();
    }
}

fn with_context<T, R, F>(compat: &mut Compat<T>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> R,
{
    let current = Current::new();
    let waker = current.as_waker();
    let mut cx = Context::from_waker(&waker);
    f(Pin::new(&mut compat.inner), &mut cx)
}

fn with_sink_context<T, Item, R, F>(compat: &mut CompatSink<T, Item>, f: F) -> R
where
    T: Unpin,
    F: FnOnce(Pin<&mut T>, &mut Context<'_>) -> R,
{
    let current = Current::new();
    let waker = current.as_waker();
    let mut cx = Context::from_waker(&waker);
    f(Pin::new(&mut compat.inner), &mut cx)
}

#[cfg(feature = "io-compat")]
mod io {
    use super::*;
    use futures_io::{AsyncRead as AsyncRead03, AsyncWrite as AsyncWrite03};
    use tokio_io::{AsyncRead as AsyncRead01, AsyncWrite as AsyncWrite01};

    fn poll_03_to_io<T>(x: task03::Poll<Result<T, std::io::Error>>)
        -> Result<T, std::io::Error>
    {
        match x {
            task03::Poll::Ready(Ok(t)) => Ok(t),
            task03::Poll::Pending => Err(std::io::ErrorKind::WouldBlock.into()),
            task03::Poll::Ready(Err(e)) => Err(e),
        }
    }

    impl<R: AsyncRead03 + Unpin> std::io::Read for Compat<R> {
        fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_io(Pin::new(&mut self.inner).poll_read(&mut cx, buf))
        }
    }

    impl<R: AsyncRead03 + Unpin> AsyncRead01 for Compat<R> {
        unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
            let initializer = self.inner.initializer();
            let does_init = initializer.should_initialize();
            if does_init {
                initializer.initialize(buf);
            }
            does_init
        }
    }

    impl<W: AsyncWrite03 + Unpin> std::io::Write for Compat<W> {
        fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_io(Pin::new(&mut self.inner).poll_write(&mut cx, buf))
        }

        fn flush(&mut self) -> std::io::Result<()> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_io(Pin::new(&mut self.inner).poll_flush(&mut cx))
        }
    }

    impl<W: AsyncWrite03 + Unpin> AsyncWrite01 for Compat<W> {
        fn shutdown(&mut self) -> std::io::Result<Async01<()>> {
            let current = Current::new();
            let waker = current.as_waker();
            let mut cx = Context::from_waker(&waker);
            poll_03_to_01(Pin::new(&mut self.inner).poll_close(&mut cx))
        }
    }
}
<|endoftext|>


<commit_before>//! Defines generally useful functions and types.

mod board_geometry;
mod zobrist_arrays;
mod move_stack;
mod notation;

pub use self::board_geometry::BoardGeometry;
pub use self::zobrist_arrays::ZobristArrays;
pub use self::move_stack::MoveStack;
pub use self::notation::parse_fen;

use depth::*;
use move_generator::MoveGenerator;

/// Performs move path enumeration.
///
/// `perft` is a debugging function to walk the move generation tree
/// of strictly legal moves and count all the leaf nodes of a certain
/// depth, which can be compared to predetermined values and used to
/// isolate bugs. In perft, nodes are only counted at the end after
/// the last `do_move`. Thus "higher" terminal nodes (e.g. mate or
/// stalemate) are not counted. Perft ignores draws by repetition, by
/// the fifty-move rule and by insufficient material. By recording the
/// amount of time taken for each iteration, it's possible to compare
/// the performance of different move generators or the same generator
/// on different machines.
pub fn perft<T: MoveGenerator>(position: &mut T, depth: Depth) -> u64 {
    if depth <= 0 {
        return 1;
    }
    let mut nodes = 0;
    let mut s = MoveStack::new();
    position.generate_all(&mut s);
    while let Some(m) = s.pop() {
        if position.do_move(m).is_some() {
            nodes += perft(position, depth - 1);
            position.undo_move(m);
        }
    }
    nodes
}
<commit_msg>optimize perft()<commit_after>//! Defines generally useful functions and types.

mod board_geometry;
mod zobrist_arrays;
mod move_stack;
mod notation;

pub use self::board_geometry::BoardGeometry;
pub use self::zobrist_arrays::ZobristArrays;
pub use self::move_stack::MoveStack;
pub use self::notation::parse_fen;

use depth::*;
use move_generator::MoveGenerator;

/// Performs move path enumeration.
///
/// `perft` is a debugging function to walk the move generation tree
/// of strictly legal moves and count all the leaf nodes of a certain
/// depth, which can be compared to predetermined values and used to
/// isolate bugs. In perft, nodes are only counted at the end after
/// the last `do_move`. Thus "higher" terminal nodes (e.g. mate or
/// stalemate) are not counted. Perft ignores draws by repetition, by
/// the fifty-move rule and by insufficient material. By recording the
/// amount of time taken for each iteration, it's possible to compare
/// the performance of different move generators or the same generator
/// on different machines.
pub fn perft<T: MoveGenerator>(position: &mut T, depth: Depth) -> u64 {
    fn pft<T: MoveGenerator>(s: &mut MoveStack, p: &mut T, d: Depth) -> u64 {
        if d <= 0 {
            return 1;
        }
        let mut nodes = 0;
        s.save();
        p.generate_all(s);
        while let Some(m) = s.pop() {
            if p.do_move(m).is_some() {
                nodes += pft(s, p, d - 1);
                p.undo_move(m);
            }
        }
        s.restore();
        nodes
    }

    let mut s = MoveStack::new();
    pft(&mut s, position, depth)
}
<|endoftext|>


<commit_before>//! Encode `InlineContent` nodes to HTML

use super::{
    attr, attr_id, attr_itemprop, attr_itemtype, attr_itemtype_str, attr_prop, concat, elem,
    elem_empty, json, EncodeContext, ToHtml,
};
use codec_txt::ToTxt;
use html_escape::encode_safe;
use std::{fs, path::PathBuf};
use stencila_schema::*;

impl ToHtml for InlineContent {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        match self {
            InlineContent::AudioObject(node) => node.to_html(slot, context),
            InlineContent::Boolean(node) => node.to_html(slot, context),
            InlineContent::Cite(node) => node.to_html(slot, context),
            InlineContent::CiteGroup(node) => node.to_html(slot, context),
            InlineContent::CodeExpression(node) => node.to_html(slot, context),
            InlineContent::CodeFragment(node) => node.to_html(slot, context),
            InlineContent::Delete(node) => node.to_html(slot, context),
            InlineContent::Emphasis(node) => node.to_html(slot, context),
            InlineContent::ImageObject(node) => node.to_html(slot, context),
            InlineContent::Integer(node) => node.to_html(slot, context),
            InlineContent::Link(node) => node.to_html(slot, context),
            InlineContent::MathFragment(node) => node.to_html(slot, context),
            InlineContent::NontextualAnnotation(node) => node.to_html(slot, context),
            InlineContent::Note(node) => node.to_html(slot, context),
            InlineContent::Null(node) => node.to_html(slot, context),
            InlineContent::Number(node) => node.to_html(slot, context),
            InlineContent::Parameter(node) => node.to_html(slot, context),
            InlineContent::Quote(node) => node.to_html(slot, context),
            InlineContent::String(node) => node.to_html(slot, context),
            InlineContent::Strong(node) => node.to_html(slot, context),
            InlineContent::Subscript(node) => node.to_html(slot, context),
            InlineContent::Superscript(node) => node.to_html(slot, context),
            InlineContent::VideoObject(node) => node.to_html(slot, context),
        }
    }
}

macro_rules! mark_to_html {
    ($type:ident, $tag:literal) => {
        impl ToHtml for $type {
            fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
                elem(
                    $tag,
                    &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
                    &self.content.to_html("", context),
                )
            }
        }
    };
}

mark_to_html!(Delete, "del");
mark_to_html!(Emphasis, "em");
mark_to_html!(NontextualAnnotation, "u");
mark_to_html!(Strong, "strong");
mark_to_html!(Subscript, "sub");
mark_to_html!(Superscript, "sup");

/// Convert a file:// URL to a data:// URI
///
/// Note that this function assumes that paths are absolute.
/// File URLs are usually resolves elsewhere e.g. in the `compile` method
/// before encoding to HTML.
fn file_uri_to_data_uri(url: &str) -> String {
    let path = if let Some(path) = url.strip_prefix("file://") {
        PathBuf::from(path)
    } else {
        return url.into();
    };

    // Read the file, convert it to a dataURI, and record it as a dependency
    match fs::read(&path) {
        Ok(bytes) => {
            let mime = match mime_guess::from_path(&path).first() {
                Some(mime) => mime.to_string(),
                None => "image/png".to_string(),
            };
            let data = base64::encode(bytes);
            ["data:", &mime, ";base64,", &data].concat()
        }
        Err(error) => {
            tracing::warn!("Unable to read media file {}: {}", path.display(), error);
            url.into()
        }
    }
}

fn content_url_to_src_attr(content_url: &str, context: &EncodeContext) -> String {
    let url = match context.bundle {
        true => file_uri_to_data_uri(content_url),
        false => content_url.to_string(),
    };
    attr("src", &url)
}

impl ToHtml for AudioObjectSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "audio",
            &[
                attr_prop(slot),
                attr_itemtype_str("AudioObject"),
                attr_id(&self.id),
                "controls".to_string(),
                content_url_to_src_attr(&self.content_url, context),
            ],
            "",
        )
    }
}

impl ToHtml for ImageObjectSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem_empty(
            "img",
            &[
                attr_prop(slot),
                attr_itemtype_str("ImageObject"),
                attr_id(&self.id),
                content_url_to_src_attr(&self.content_url, context),
            ],
        )
    }
}

impl ToHtml for VideoObjectSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let src_attr = content_url_to_src_attr(&self.content_url, context);
        let type_attr = match &self.media_type {
            Some(media_type) => attr("type", media_type),
            None => "".to_string(),
        };
        elem(
            "video",
            &[
                attr_prop(slot),
                attr_itemtype_str("VideoObject"),
                attr_id(&self.id),
                "controls".to_string(),
            ],
            &elem("source", &[src_attr, type_attr], ""),
        )
    }
}

impl ToHtml for Cite {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let content = match &self.content {
            Some(nodes) => nodes.to_html("", context),
            None => {
                // Get the list of references from the root nodes
                let references = match context.root {
                    Node::Article(article) => article.references.clone(),
                    Node::CreativeWork(work) => work.references.clone(),
                    _ => {
                        tracing::warn!("Unhandled root document type");
                        None
                    }
                };
                if let Some(references) = references {
                    // Find the reference that matches the `target`
                    let reference = references
                        .iter()
                        .enumerate()
                        .find_map(|(index, reference)| match reference {
                            // A string reference so match against its index in the references list
                            CreativeWorkReferences::String(_) => {
                                if self.target == format!("ref{}", index + 1)
                                    || self.target == format!("ref{}", index + 1)
                                {
                                    Some((index, reference))
                                } else {
                                    None
                                }
                            }
                            // A `CreativeWork` reference so match against its `id`/
                            CreativeWorkReferences::CreativeWorkTypes(work) => match work {
                                CreativeWorkTypes::Article(Article { id, .. }) => {
                                    if let Some(id) = id.as_deref() {
                                        if self.target == *id {
                                            Some((index, reference))
                                        } else {
                                            None
                                        }
                                    } else {
                                        None
                                    }
                                }
                                _ => None,
                            },
                        });
                    // Create the content for the citation
                    match reference {
                        None => {
                            tracing::warn!("When encoding citation was unable to find reference '{}' in root document", self.target);
                            format!(r#"{}"#, self.target.clone())
                        }
                        Some((index, reference)) => {
                            // Always have a numeric citation
                            let mut content = format!(r#"{}"#, index + 1);
                            // If a `CreativeWorkType` then add authors and year
                            if let CreativeWorkReferences::CreativeWorkTypes(work) = reference {
                                let (authors, date) = match &work {
                                    CreativeWorkTypes::Article(article) => {
                                        (article.authors.clone(), article.date_published.clone())
                                    }
                                    CreativeWorkTypes::CreativeWork(work) => {
                                        (work.authors.clone(), work.date_published.clone())
                                    }
                                    _ => {
                                        tracing::warn!("Unhandled root document type");
                                        (None, None)
                                    }
                                };
                                if let Some(authors) = authors {
                                    let names: Vec<String> = authors
                                        .iter()
                                        .map(|author| match author {
                                            CreativeWorkAuthors::Person(person) => {
                                                match &person.family_names {
                                                    Some(family_names) => family_names.join(" "),
                                                    None => "Anonymous".to_string(),
                                                }
                                            }
                                            CreativeWorkAuthors::Organization(org) => {
                                                match &org.name {
                                                    Some(name) => *name.clone(),
                                                    None => "Anonymous".to_string(),
                                                }
                                            }
                                        })
                                        .collect();
                                    let names = if authors.len() == 1 {
                                        names.join("")
                                    } else if authors.len() == 2 {
                                        format!(r#"{} and {}"#, names[0], names[1])
                                    } else {
                                        format!(r#"{} et al"#, names[0])
                                    };
                                    content += &format!(r#"{}"#, names)
                                }
                                if let Some(date) = date {
                                    if date.value.len() >= 4 {
                                        let year = date.value[..4].to_string();
                                        content += &format!(r#"{}"#, year)
                                    }
                                }
                            }
                            content
                        }
                    }
                } else {
                    tracing::warn!("When encoding citation was unable to find references list in root document");
                    format!(r#"{}"#, self.target.clone())
                }
            }
        };
        elem(
            "cite",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &elem("a", &[attr("href", &self.target)], &content),
        )
    }
}

impl ToHtml for CiteGroup {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "span",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &concat(&self.items, |cite| cite.to_html("", context)),
        )
    }
}

impl ToHtml for CodeExpression {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let output = match &self.output {
            Some(output) => output.to_html("", context),
            None => "".to_string(),
        };
        elem(
            "stencila-code-expression",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("programming-language", &self.programming_language),
            ],
            &[
                elem("code", &[attr("slot", "text")], &encode_safe(&self.text)),
                elem("output", &[attr("slot", "output")], &output),
            ]
            .concat(),
        )
    }
}

impl ToHtml for CodeFragment {
    /// Encode a [`CodeFragment`] as HTML
    ///
    /// See `CodeBlock::to_html` for why `programming_language` is encoded
    /// as both a `class` attribute and a `<meta>` element.
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let (class, meta) = match &self.programming_language {
            Some(programming_language) => (
                attr("class", &["language-", programming_language].concat()),
                elem_empty(
                    "meta",
                    &[
                        attr_itemprop("programming_language"),
                        attr("content", programming_language),
                    ],
                ),
            ),
            None => ("".to_string(), "".to_string()),
        };

        let text = encode_safe(&self.text);

        elem(
            "code",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                class,
            ],
            &[meta, text.to_string()].concat(),
        )
    }
}

impl ToHtml for Link {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "a",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("href", &self.target),
            ],
            &self.content.to_html("", context),
        )
    }
}

impl ToHtml for MathFragment {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "code",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &encode_safe(&self.text),
        )
    }
}

impl ToHtml for Note {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "code",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("class", "todo"),
            ],
            &json(self),
        )
    }
}

impl ToHtml for Parameter {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let input_type = match self.validator.as_deref() {
            Some(ValidatorTypes::NumberValidator(..)) => "number",
            _ => "text",
        };
        let value_attr = match self.value.as_deref() {
            Some(node) => attr("value", &node.to_txt()),
            _ => "".to_string(),
        };
        elem_empty(
            "input",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("type", input_type),
                attr("name", &self.name),
                value_attr,
            ],
        )
    }
}

impl ToHtml for Quote {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "q",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}
<commit_msg>chore(HTML encoding): Do not wrap strings when inline content<commit_after>//! Encode `InlineContent` nodes to HTML

use super::{
    attr, attr_id, attr_itemprop, attr_itemtype, attr_itemtype_str, attr_prop, concat, elem,
    elem_empty, json, EncodeContext, ToHtml,
};
use codec_txt::ToTxt;
use html_escape::encode_safe;
use std::{fs, path::PathBuf};
use stencila_schema::*;

impl ToHtml for InlineContent {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        match self {
            InlineContent::AudioObject(node) => node.to_html(slot, context),
            InlineContent::Boolean(node) => node.to_html(slot, context),
            InlineContent::Cite(node) => node.to_html(slot, context),
            InlineContent::CiteGroup(node) => node.to_html(slot, context),
            InlineContent::CodeExpression(node) => node.to_html(slot, context),
            InlineContent::CodeFragment(node) => node.to_html(slot, context),
            InlineContent::Delete(node) => node.to_html(slot, context),
            InlineContent::Emphasis(node) => node.to_html(slot, context),
            InlineContent::ImageObject(node) => node.to_html(slot, context),
            InlineContent::Integer(node) => node.to_html(slot, context),
            InlineContent::Link(node) => node.to_html(slot, context),
            InlineContent::MathFragment(node) => node.to_html(slot, context),
            InlineContent::NontextualAnnotation(node) => node.to_html(slot, context),
            InlineContent::Note(node) => node.to_html(slot, context),
            InlineContent::Null(node) => node.to_html(slot, context),
            InlineContent::Number(node) => node.to_html(slot, context),
            InlineContent::Parameter(node) => node.to_html(slot, context),
            InlineContent::Quote(node) => node.to_html(slot, context),
            // Note: to reduce extraneous elements, when a part of inline content, strings
            // are encoded without a wrapping .
            InlineContent::String(node) => encode_safe(node).to_string(),
            InlineContent::Strong(node) => node.to_html(slot, context),
            InlineContent::Subscript(node) => node.to_html(slot, context),
            InlineContent::Superscript(node) => node.to_html(slot, context),
            InlineContent::VideoObject(node) => node.to_html(slot, context),
        }
    }
}

macro_rules! mark_to_html {
    ($type:ident, $tag:literal) => {
        impl ToHtml for $type {
            fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
                elem(
                    $tag,
                    &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
                    &self.content.to_html("", context),
                )
            }
        }
    };
}

mark_to_html!(Delete, "del");
mark_to_html!(Emphasis, "em");
mark_to_html!(NontextualAnnotation, "u");
mark_to_html!(Strong, "strong");
mark_to_html!(Subscript, "sub");
mark_to_html!(Superscript, "sup");

/// Convert a file:// URL to a data:// URI
///
/// Note that this function assumes that paths are absolute.
/// File URLs are usually resolves elsewhere e.g. in the `compile` method
/// before encoding to HTML.
fn file_uri_to_data_uri(url: &str) -> String {
    let path = if let Some(path) = url.strip_prefix("file://") {
        PathBuf::from(path)
    } else {
        return url.into();
    };

    // Read the file, convert it to a dataURI, and record it as a dependency
    match fs::read(&path) {
        Ok(bytes) => {
            let mime = match mime_guess::from_path(&path).first() {
                Some(mime) => mime.to_string(),
                None => "image/png".to_string(),
            };
            let data = base64::encode(bytes);
            ["data:", &mime, ";base64,", &data].concat()
        }
        Err(error) => {
            tracing::warn!("Unable to read media file {}: {}", path.display(), error);
            url.into()
        }
    }
}

fn content_url_to_src_attr(content_url: &str, context: &EncodeContext) -> String {
    let url = match context.bundle {
        true => file_uri_to_data_uri(content_url),
        false => content_url.to_string(),
    };
    attr("src", &url)
}

impl ToHtml for AudioObjectSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "audio",
            &[
                attr_prop(slot),
                attr_itemtype_str("AudioObject"),
                attr_id(&self.id),
                "controls".to_string(),
                content_url_to_src_attr(&self.content_url, context),
            ],
            "",
        )
    }
}

impl ToHtml for ImageObjectSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem_empty(
            "img",
            &[
                attr_prop(slot),
                attr_itemtype_str("ImageObject"),
                attr_id(&self.id),
                content_url_to_src_attr(&self.content_url, context),
            ],
        )
    }
}

impl ToHtml for VideoObjectSimple {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let src_attr = content_url_to_src_attr(&self.content_url, context);
        let type_attr = match &self.media_type {
            Some(media_type) => attr("type", media_type),
            None => "".to_string(),
        };
        elem(
            "video",
            &[
                attr_prop(slot),
                attr_itemtype_str("VideoObject"),
                attr_id(&self.id),
                "controls".to_string(),
            ],
            &elem("source", &[src_attr, type_attr], ""),
        )
    }
}

impl ToHtml for Cite {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let content = match &self.content {
            Some(nodes) => nodes.to_html("", context),
            None => {
                // Get the list of references from the root nodes
                let references = match context.root {
                    Node::Article(article) => article.references.clone(),
                    Node::CreativeWork(work) => work.references.clone(),
                    _ => {
                        tracing::warn!("Unhandled root document type");
                        None
                    }
                };
                if let Some(references) = references {
                    // Find the reference that matches the `target`
                    let reference = references
                        .iter()
                        .enumerate()
                        .find_map(|(index, reference)| match reference {
                            // A string reference so match against its index in the references list
                            CreativeWorkReferences::String(_) => {
                                if self.target == format!("ref{}", index + 1)
                                    || self.target == format!("ref{}", index + 1)
                                {
                                    Some((index, reference))
                                } else {
                                    None
                                }
                            }
                            // A `CreativeWork` reference so match against its `id`/
                            CreativeWorkReferences::CreativeWorkTypes(work) => match work {
                                CreativeWorkTypes::Article(Article { id, .. }) => {
                                    if let Some(id) = id.as_deref() {
                                        if self.target == *id {
                                            Some((index, reference))
                                        } else {
                                            None
                                        }
                                    } else {
                                        None
                                    }
                                }
                                _ => None,
                            },
                        });
                    // Create the content for the citation
                    match reference {
                        None => {
                            tracing::warn!("When encoding citation was unable to find reference '{}' in root document", self.target);
                            format!(r#"{}"#, self.target.clone())
                        }
                        Some((index, reference)) => {
                            // Always have a numeric citation
                            let mut content = format!(r#"{}"#, index + 1);
                            // If a `CreativeWorkType` then add authors and year
                            if let CreativeWorkReferences::CreativeWorkTypes(work) = reference {
                                let (authors, date) = match &work {
                                    CreativeWorkTypes::Article(article) => {
                                        (article.authors.clone(), article.date_published.clone())
                                    }
                                    CreativeWorkTypes::CreativeWork(work) => {
                                        (work.authors.clone(), work.date_published.clone())
                                    }
                                    _ => {
                                        tracing::warn!("Unhandled root document type");
                                        (None, None)
                                    }
                                };
                                if let Some(authors) = authors {
                                    let names: Vec<String> = authors
                                        .iter()
                                        .map(|author| match author {
                                            CreativeWorkAuthors::Person(person) => {
                                                match &person.family_names {
                                                    Some(family_names) => family_names.join(" "),
                                                    None => "Anonymous".to_string(),
                                                }
                                            }
                                            CreativeWorkAuthors::Organization(org) => {
                                                match &org.name {
                                                    Some(name) => *name.clone(),
                                                    None => "Anonymous".to_string(),
                                                }
                                            }
                                        })
                                        .collect();
                                    let names = if authors.len() == 1 {
                                        names.join("")
                                    } else if authors.len() == 2 {
                                        format!(r#"{} and {}"#, names[0], names[1])
                                    } else {
                                        format!(r#"{} et al"#, names[0])
                                    };
                                    content += &format!(r#"{}"#, names)
                                }
                                if let Some(date) = date {
                                    if date.value.len() >= 4 {
                                        let year = date.value[..4].to_string();
                                        content += &format!(r#"{}"#, year)
                                    }
                                }
                            }
                            content
                        }
                    }
                } else {
                    tracing::warn!("When encoding citation was unable to find references list in root document");
                    format!(r#"{}"#, self.target.clone())
                }
            }
        };
        elem(
            "cite",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &elem("a", &[attr("href", &self.target)], &content),
        )
    }
}

impl ToHtml for CiteGroup {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "span",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &concat(&self.items, |cite| cite.to_html("", context)),
        )
    }
}

impl ToHtml for CodeExpression {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        let output = match &self.output {
            Some(output) => output.to_html("", context),
            None => "".to_string(),
        };
        elem(
            "stencila-code-expression",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("programming-language", &self.programming_language),
            ],
            &[
                elem("code", &[attr("slot", "text")], &encode_safe(&self.text)),
                elem("output", &[attr("slot", "output")], &output),
            ]
            .concat(),
        )
    }
}

impl ToHtml for CodeFragment {
    /// Encode a [`CodeFragment`] as HTML
    ///
    /// See `CodeBlock::to_html` for why `programming_language` is encoded
    /// as both a `class` attribute and a `<meta>` element.
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let (class, meta) = match &self.programming_language {
            Some(programming_language) => (
                attr("class", &["language-", programming_language].concat()),
                elem_empty(
                    "meta",
                    &[
                        attr_itemprop("programming_language"),
                        attr("content", programming_language),
                    ],
                ),
            ),
            None => ("".to_string(), "".to_string()),
        };

        let text = encode_safe(&self.text);

        elem(
            "code",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                class,
            ],
            &[meta, text.to_string()].concat(),
        )
    }
}

impl ToHtml for Link {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "a",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("href", &self.target),
            ],
            &self.content.to_html("", context),
        )
    }
}

impl ToHtml for MathFragment {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "code",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &encode_safe(&self.text),
        )
    }
}

impl ToHtml for Note {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        elem(
            "code",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("class", "todo"),
            ],
            &json(self),
        )
    }
}

impl ToHtml for Parameter {
    fn to_html(&self, slot: &str, _context: &EncodeContext) -> String {
        let input_type = match self.validator.as_deref() {
            Some(ValidatorTypes::NumberValidator(..)) => "number",
            _ => "text",
        };
        let value_attr = match self.value.as_deref() {
            Some(node) => attr("value", &node.to_txt()),
            _ => "".to_string(),
        };
        elem_empty(
            "input",
            &[
                attr_prop(slot),
                attr_itemtype::<Self>(),
                attr_id(&self.id),
                attr("type", input_type),
                attr("name", &self.name),
                value_attr,
            ],
        )
    }
}

impl ToHtml for Quote {
    fn to_html(&self, slot: &str, context: &EncodeContext) -> String {
        elem(
            "q",
            &[attr_prop(slot), attr_itemtype::<Self>(), attr_id(&self.id)],
            &self.content.to_html("", context),
        )
    }
}
<|endoftext|>


<commit_before>//! The `image` element.

use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::Href;
use crate::aspect_ratio::AspectRatio;
use crate::bbox::BoundingBox;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::{DrawingCtx, ViewParams};
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::*;
use crate::href::{is_href, set_href};
use crate::length::*;
use crate::node::{CascadedValues, Node};
use crate::parsers::ParseValue;
use crate::properties::ComputedValues;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;

#[derive(Default)]
pub struct Image {
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: Length<Horizontal>,
    height: Length<Vertical>,
    aspect: AspectRatio,
    href: Option<Href>,
}

impl SetAttributes for Image {
    fn set_attributes(&mut self, pbag: &PropertyBag<'_>) -> ElementResult {
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => {
                    self.width = attr.parse_and_validate(value, Length::check_nonnegative)?
                }
                expanded_name!("", "height") => {
                    self.height = attr.parse_and_validate(value, Length::check_nonnegative)?
                }
                expanded_name!("", "preserveAspectRatio") => self.aspect = attr.parse(value)?,

                // "path" is used by some older Adobe Illustrator versions
                ref a if is_href(a) || *a == expanded_name!("", "path") => {
                    let href = Href::parse(value)
                        .map_err(|_| ValueErrorKind::parse_error("could not parse href"))
                        .attribute(attr.clone())?;

                    set_href(a, &mut self.href, href);
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Image {
    fn draw(
        &self,
        node: &Node,
        acquired_nodes: &mut AcquiredNodes,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        if self.href.is_none() {
            return Ok(draw_ctx.empty_bbox());
        }

        let href = self.href.as_ref().unwrap();
        let surface = match *href {
            Href::PlainUrl(ref url) => match acquired_nodes.lookup_image(url) {
                Ok(surf) => surf,
                Err(e) => {
                    rsvg_log!("could not load image \"{}\": {}", url, e);
                    return Ok(draw_ctx.empty_bbox());
                }
            },
            Href::WithFragment(_) => {
                rsvg_log!(
                    "not rendering {} because its href cannot contain a fragment identifier",
                    node
                );

                return Ok(draw_ctx.empty_bbox());
            }
        };

        let values = cascaded.get();
        let params = draw_ctx.get_view_params();
        let rect = self.get_rect(values, &params);

        draw_ctx.draw_image(
            &surface,
            rect,
            self.aspect,
            node,
            acquired_nodes,
            values,
            clipping,
        )
    }
}

impl Image {
    fn get_rect(&self, values: &ComputedValues, params: &ViewParams) -> Rect {
        let x = self.x.normalize(&values, &params);
        let y = self.y.normalize(&values, &params);
        let w = self.width.normalize(&values, &params);
        let h = self.height.normalize(&values, &params);

        Rect::new(x, y, x + w, y + h)
    }
}
<commit_msg>image: shorten code<commit_after>//! The `image` element.

use markup5ever::{expanded_name, local_name, namespace_url, ns};

use crate::allowed_url::Href;
use crate::aspect_ratio::AspectRatio;
use crate::bbox::BoundingBox;
use crate::document::AcquiredNodes;
use crate::drawing_ctx::DrawingCtx;
use crate::element::{Draw, ElementResult, SetAttributes};
use crate::error::*;
use crate::href::{is_href, set_href};
use crate::length::*;
use crate::node::{CascadedValues, Node};
use crate::parsers::ParseValue;
use crate::property_bag::PropertyBag;
use crate::rect::Rect;

#[derive(Default)]
pub struct Image {
    x: Length<Horizontal>,
    y: Length<Vertical>,
    width: Length<Horizontal>,
    height: Length<Vertical>,
    aspect: AspectRatio,
    href: Option<Href>,
}

impl SetAttributes for Image {
    fn set_attributes(&mut self, pbag: &PropertyBag<'_>) -> ElementResult {
        for (attr, value) in pbag.iter() {
            match attr.expanded() {
                expanded_name!("", "x") => self.x = attr.parse(value)?,
                expanded_name!("", "y") => self.y = attr.parse(value)?,
                expanded_name!("", "width") => {
                    self.width = attr.parse_and_validate(value, Length::check_nonnegative)?
                }
                expanded_name!("", "height") => {
                    self.height = attr.parse_and_validate(value, Length::check_nonnegative)?
                }
                expanded_name!("", "preserveAspectRatio") => self.aspect = attr.parse(value)?,

                // "path" is used by some older Adobe Illustrator versions
                ref a if is_href(a) || *a == expanded_name!("", "path") => {
                    let href = Href::parse(value)
                        .map_err(|_| ValueErrorKind::parse_error("could not parse href"))
                        .attribute(attr.clone())?;

                    set_href(a, &mut self.href, href);
                }

                _ => (),
            }
        }

        Ok(())
    }
}

impl Draw for Image {
    fn draw(
        &self,
        node: &Node,
        acquired_nodes: &mut AcquiredNodes,
        cascaded: &CascadedValues<'_>,
        draw_ctx: &mut DrawingCtx,
        clipping: bool,
    ) -> Result<BoundingBox, RenderingError> {
        let surface = match self.href {
            Some(Href::PlainUrl(ref url)) => match acquired_nodes.lookup_image(url) {
                Ok(surf) => surf,
                Err(e) => {
                    rsvg_log!("could not load image \"{}\": {}", url, e);
                    return Ok(draw_ctx.empty_bbox());
                }
            },
            Some(_) => {
                rsvg_log!(
                    "not rendering {} because its href cannot contain a fragment identifier",
                    node
                );

                return Ok(draw_ctx.empty_bbox());
            }
            None => return Ok(draw_ctx.empty_bbox()),
        };

        let values = cascaded.get();

        let params = draw_ctx.get_view_params();
        let x = self.x.normalize(&values, &params);
        let y = self.y.normalize(&values, &params);
        let w = self.width.normalize(&values, &params);
        let h = self.height.normalize(&values, &params);

        draw_ctx.draw_image(
            &surface,
            Rect::new(x, y, x + w, y + h),
            self.aspect,
            node,
            acquired_nodes,
            values,
            clipping,
        )
    }
}
<|endoftext|>


<commit_before>use csv;
use error;
use std::io;
use value;
use ordered_float;

pub struct CsvSource<R>(csv::StringRecordsIntoIter<R>) where R: io::Read;

pub struct CsvSink<W>(csv::Writer<W>) where W: io::Write;

#[inline]
pub fn source<R>(r: R) -> CsvSource<R> where R: io::Read
{
    CsvSource(csv::ReaderBuilder::new()
                  .has_headers(false)
                  .from_reader(r)
                  .into_records())
}

#[inline]
pub fn sink<W>(w: W) -> CsvSink<W> where W: io::Write
{
    CsvSink(csv::Writer::from_writer(w))
}

impl<R> value::Source for CsvSource<R> where R: io::Read
{
    #[inline]
    fn read(&mut self) -> error::Result<Option<value::Value>> {
        match self.0.next() {
            Some(Ok(v)) => Ok(Some(value::Value::Sequence(
                v.iter().map(|s| value::Value::String(s.to_string())).collect()
            ))),
            Some(Err(e)) => Err(error::Error::from(e)),
            None => Ok(None),
        }
    }
}

impl<W> value::Sink for CsvSink<W> where W: io::Write
{
    #[inline]
    fn write(&mut self, value: value::Value) -> error::Result<()> {
        match value {
            value::Value::Sequence(seq) => {
                let record: Vec<String> = seq.into_iter().map(value_to_csv).collect();
                self.0.write_record(record)?;
                Ok(())
            }
            x => bail!("csv can only output sequences, got: {:?}", x)
        }
    }
}

fn value_to_csv(value: value::Value) -> String {
    match value {
        value::Value::Unit => panic!("csv cannot output nested Unit"),
        value::Value::Bool(v) => format!("{}", v),

        value::Value::I8(v) => format!("{}", v),
        value::Value::I16(v) => format!("{}", v),
        value::Value::I32(v) => format!("{}", v),
        value::Value::I64(v) => format!("{}", v),

        value::Value::U8(v) => format!("{}", v),
        value::Value::U16(v) => format!("{}", v),
        value::Value::U32(v) => format!("{}", v),
        value::Value::U64(v) => format!("{}", v),

        value::Value::F32(ordered_float::OrderedFloat(v)) => format!("{}", v),
        value::Value::F64(ordered_float::OrderedFloat(v)) => format!("{}", v),

        value::Value::Char(v) => format!("{}", v),
        value::Value::String(v) => format!("{}", v),
        value::Value::Bytes(_) => panic!("csv cannot output nested bytes"),

        value::Value::Sequence(_) => panic!("csv cannot output nested sequences"),
        value::Value::Map(_) => panic!("csv cannot output nested maps")
    }
}
<commit_msg>Improve error handling<commit_after>use csv;
use error;
use std::io;
use value;
use ordered_float;

pub struct CsvSource<R>(csv::StringRecordsIntoIter<R>) where R: io::Read;

pub struct CsvSink<W>(csv::Writer<W>) where W: io::Write;

#[inline]
pub fn source<R>(r: R) -> CsvSource<R> where R: io::Read
{
    CsvSource(csv::ReaderBuilder::new()
                  .has_headers(false)
                  .from_reader(r)
                  .into_records())
}

#[inline]
pub fn sink<W>(w: W) -> CsvSink<W> where W: io::Write
{
    CsvSink(csv::Writer::from_writer(w))
}

impl<R> value::Source for CsvSource<R> where R: io::Read
{
    #[inline]
    fn read(&mut self) -> error::Result<Option<value::Value>> {
        match self.0.next() {
            Some(Ok(v)) => Ok(Some(value::Value::Sequence(
                v.iter().map(|s| value::Value::String(s.to_string())).collect()
            ))),
            Some(Err(e)) => Err(error::Error::from(e)),
            None => Ok(None),
        }
    }
}

impl<W> value::Sink for CsvSink<W> where W: io::Write
{
    #[inline]
    fn write(&mut self, value: value::Value) -> error::Result<()> {
        match value {
            value::Value::Sequence(seq) => {
                let record: Vec<String> =
                    seq.into_iter().map(value_to_csv).collect::<error::Result<Vec<_>>>()?;
                self.0.write_record(record)?;
                Ok(())
            }
            x => bail!("csv can only output sequences, got: {:?}", x)
        }
    }
}

fn value_to_csv(value: value::Value) -> error::Result<String> {
    match value {
        value::Value::Unit => bail!("csv cannot output nested Unit"),
        value::Value::Bool(v) => Ok(format!("{}", v)),

        value::Value::I8(v) => Ok(format!("{}", v)),
        value::Value::I16(v) => Ok(format!("{}", v)),
        value::Value::I32(v) => Ok(format!("{}", v)),
        value::Value::I64(v) => Ok(format!("{}", v)),

        value::Value::U8(v) => Ok(format!("{}", v)),
        value::Value::U16(v) => Ok(format!("{}", v)),
        value::Value::U32(v) => Ok(format!("{}", v)),
        value::Value::U64(v) => Ok(format!("{}", v)),

        value::Value::F32(ordered_float::OrderedFloat(v)) => Ok(format!("{}", v)),
        value::Value::F64(ordered_float::OrderedFloat(v)) => Ok(format!("{}", v)),

        value::Value::Char(v) => Ok(format!("{}", v)),
        value::Value::String(v) => Ok(format!("{}", v)),
        value::Value::Bytes(_) => bail!("csv cannot output nested bytes"),

        value::Value::Sequence(_) => bail!("csv cannot output nested sequences"),
        value::Value::Map(_) => bail!("csv cannot output nested maps")
    }
}
<|endoftext|>


<commit_before>use crate::utils::span_lint;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Detects passing a mutable reference to a function that only
    /// requires an immutable reference.
    ///
    /// **Why is this bad?** The immutable reference rules out all other references
    /// to the value. Also the code misleads about the intent of the call site.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// // Bad
    /// my_vec.push(&mut value)
    ///
    /// // Good
    /// my_vec.push(&value)
    /// ```
    pub UNNECESSARY_MUT_PASSED,
    style,
    "an argument passed as a mutable reference although the callee only demands an immutable reference"
}

declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Call(ref fn_expr, ref arguments) => {
                if let ExprKind::Path(ref path) = fn_expr.kind {
                    check_arguments(
                        cx,
                        arguments,
                        cx.typeck_results().expr_ty(fn_expr),
                        &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                        "function",
                    );
                }
            },
            ExprKind::MethodCall(ref path, _, ref arguments, _) => {
                let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                let substs = cx.typeck_results().node_substs(e.hir_id);
                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
            },
            _ => (),
        }
    }
}

fn check_arguments<'tcx>(
    cx: &LateContext<'tcx>,
    arguments: &[Expr<'_>],
    type_definition: Ty<'tcx>,
    name: &str,
    fn_kind: &str,
) {
    match type_definition.kind {
        ty::FnDef(..) | ty::FnPtr(_) => {
            let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
            for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
                match parameter.kind {
                    ty::Ref(_, _, Mutability::Not)
                    | ty::RawPtr(ty::TypeAndMut {
                        mutbl: Mutability::Not, ..
                    }) => {
                        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
                            span_lint(
                                cx,
                                UNNECESSARY_MUT_PASSED,
                                argument.span,
                                &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name),
                            );
                        }
                    },
                    _ => (),
                }
            }
        },
        _ => (),
    }
}
<commit_msg>Fix typo in description of unnecessary_mut_passed<commit_after>use crate::utils::span_lint;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};

declare_clippy_lint! {
    /// **What it does:** Detects passing a mutable reference to a function that only
    /// requires an immutable reference.
    ///
    /// **Why is this bad?** The mutable reference rules out all other references to
    /// the value. Also the code misleads about the intent of the call site.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```ignore
    /// // Bad
    /// my_vec.push(&mut value)
    ///
    /// // Good
    /// my_vec.push(&value)
    /// ```
    pub UNNECESSARY_MUT_PASSED,
    style,
    "an argument passed as a mutable reference although the callee only demands an immutable reference"
}

declare_lint_pass!(UnnecessaryMutPassed => [UNNECESSARY_MUT_PASSED]);

impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
        match e.kind {
            ExprKind::Call(ref fn_expr, ref arguments) => {
                if let ExprKind::Path(ref path) = fn_expr.kind {
                    check_arguments(
                        cx,
                        arguments,
                        cx.typeck_results().expr_ty(fn_expr),
                        &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
                        "function",
                    );
                }
            },
            ExprKind::MethodCall(ref path, _, ref arguments, _) => {
                let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap();
                let substs = cx.typeck_results().node_substs(e.hir_id);
                let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs);
                check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method")
            },
            _ => (),
        }
    }
}

fn check_arguments<'tcx>(
    cx: &LateContext<'tcx>,
    arguments: &[Expr<'_>],
    type_definition: Ty<'tcx>,
    name: &str,
    fn_kind: &str,
) {
    match type_definition.kind {
        ty::FnDef(..) | ty::FnPtr(_) => {
            let parameters = type_definition.fn_sig(cx.tcx).skip_binder().inputs();
            for (argument, parameter) in arguments.iter().zip(parameters.iter()) {
                match parameter.kind {
                    ty::Ref(_, _, Mutability::Not)
                    | ty::RawPtr(ty::TypeAndMut {
                        mutbl: Mutability::Not, ..
                    }) => {
                        if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _) = argument.kind {
                            span_lint(
                                cx,
                                UNNECESSARY_MUT_PASSED,
                                argument.span,
                                &format!("the {} `{}` doesn't need a mutable reference", fn_kind, name),
                            );
                        }
                    },
                    _ => (),
                }
            }
        },
        _ => (),
    }
}
<|endoftext|>