<commit_before>use core::result::{Result, Err, Ok};
use core::cast;
use core::libc::{c_void, c_int, c_char};
use core::str;
use core::vec;

use sdl;
use ll;
use util::Rect;

pub enum SurfaceFlag {
    SWSurface = 0x00000000,
    HWSurface = 0x00000001,
    AsyncBlit = 0x00000004,
}

pub enum VideoModeFlag {
    AnyFormat = 0x10000000,
    HWPalette = 0x20000000,
    DoubleBuf = 0x40000000,
    Fullscreen = 0x80000000,
    OpenGL = 0x00000002,
    OpenGLBlit = 0x0000000A,
    Resizable  = 0x00000010,
    NoFrame = 0x00000020,
}

pub struct Surface {
    priv raw_surface: *ll::video::SDL_Surface,
}

impl Surface {

    fn display_format() -> Result<~Surface, ~str> {
        let raw_surface = ll::video::SDL_DisplayFormat(self.raw_surface);
        if raw_surface == ptr::null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface{ raw_surface: raw_surface })
        }
    }

    fn flip() -> bool {
        ll::video::SDL_Flip(self.raw_surface) == 0 as c_int
    }

    fn lock() -> bool {
        return ll::video::SDL_LockSurface(self.raw_surface) == 0 as c_int;
    }

    fn unlock() -> bool {
        return ll::video::SDL_UnlockSurface(self.raw_surface) == 0 as c_int;
    }

    fn blit_surface_rect(src: &Surface, srcrect: &Rect, dstrect: &Rect) -> bool {
        let res = ll::video::SDL_UpperBlit(src.raw_surface, srcrect, self.raw_surface, dstrect);
        return res == 0 as c_int;
    }

    fn blit_surface(src: &Surface) -> bool {
        let res = ll::video::SDL_UpperBlit(src.raw_surface, ptr::null(), self.raw_surface, ptr::null());
        return res == 0 as c_int;
    }

    fn fill_rect(rect: &Rect, color: u32) -> bool {
        return ll::video::SDL_FillRect(self.raw_surface, rect, color) == 0 as c_int;
    }

    fn fill(color: u32) -> bool {
        return ll::video::SDL_FillRect(self.raw_surface, ptr::null(), color) == 0 as c_int;
    }
}

impl Surface : Drop {

    fn finalize(&self) {
        ll::video::SDL_FreeSurface(self.raw_surface)
    }
}

//FIXME: This needs to be called multiple times on window resize, so Drop is going to do bad things, possibly. Test it out.
//Consider making videomode surfaces their own type, with a reset method?
pub fn set_video_mode(
    width: int,
    height: int,
    bitsperpixel: int,
    surface_flags: &[SurfaceFlag],
    video_mode_flags: &[VideoModeFlag]) -> Result<~Surface, ~str> {
    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });
    let flags = vec::foldl(flags, video_mode_flags, |flags, flag| {
        flags | *flag as u32
    });

    let raw_surface = ll::video::SDL_SetVideoMode(width as c_int, height as c_int, bitsperpixel as c_int, flags);

    if raw_surface == ptr::null() {
        Err(sdl::get_error())
    } else {
        Ok(~Surface{ raw_surface: raw_surface })
    }
}

pub fn load_bmp(file: &str) -> Result<~Surface, ~str> unsafe {
    str::as_buf(file, |buf, _len| {
        let buf = cast::reinterpret_cast(&buf);
        str::as_buf(~"rb", |rbbuf, _len| {
            let rbbuf = cast::reinterpret_cast(&rbbuf);
            let raw_surface = ll::video::SDL_LoadBMP_RW(ll::video::SDL_RWFromFile(buf, rbbuf), 1 as c_int);
            if raw_surface == ptr::null() {
                Err(sdl::get_error())
            } else {
                Ok(~Surface{ raw_surface: raw_surface })
            }
        })
    })
}

pub fn create_rgb_surface(
    surface_flags: &[SurfaceFlag],
    width: int, height: int, bits_per_pixel: int,
    rmask: u32, gmask: u32, bmask: u32, amask: u32) -> Result<~Surface, ~str> {

    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });

    let raw_surface = ll::video::SDL_CreateRGBSurface(
        flags, width as c_int, height as c_int, bits_per_pixel as c_int,
        rmask, gmask, bmask, amask);
    if raw_surface == ptr::null() {
        Err(sdl::get_error())
    } else {
        Ok(~Surface{ raw_surface: raw_surface })
    }
}
<commit_msg>Add a safe locking function for direct pixel access<commit_after>use sdl;
use ll;
use util::Rect;

use core::result::{Result, Err, Ok};
use core::cast::transmute;
use core::cast;
use core::libc::{c_void, c_int, c_char};
use core::str;
use core::vec;

pub enum SurfaceFlag {
    SWSurface = 0x00000000,
    HWSurface = 0x00000001,
    AsyncBlit = 0x00000004,
}

pub enum VideoModeFlag {
    AnyFormat = 0x10000000,
    HWPalette = 0x20000000,
    DoubleBuf = 0x40000000,
    Fullscreen = 0x80000000,
    OpenGL = 0x00000002,
    OpenGLBlit = 0x0000000A,
    Resizable  = 0x00000010,
    NoFrame = 0x00000020,
}

pub struct Surface {
    priv raw_surface: *ll::video::SDL_Surface,
}

pub impl Surface {
    fn display_format(&self) -> Result<~Surface, ~str> {
        let raw_surface = ll::video::SDL_DisplayFormat(self.raw_surface);
        if raw_surface == ptr::null() {
            Err(sdl::get_error())
        } else {
            Ok(~Surface{ raw_surface: raw_surface })
        }
    }

    fn flip(&self) -> bool {
        ll::video::SDL_Flip(self.raw_surface) == 0 as c_int
    }

    /// Locks a surface so that the pixels can be directly accessed safely.
    fn with_lock<R>(&self, f: &fn(pixels: &mut [u8]) -> R) -> R {
        unsafe {
            if ll::video::SDL_LockSurface(self.raw_surface) != 0 { fail; }
            let len = (*self.raw_surface).pitch as uint * ((*self.raw_surface).h as uint);
            let pixels: &mut [u8] = transmute(((*self.raw_surface).pixels, len));
            let rv = f(pixels);
            if ll::video::SDL_UnlockSurface(self.raw_surface) != 0 { fail; }
            rv
        }
    }

    fn lock(&self) -> bool {
        return ll::video::SDL_LockSurface(self.raw_surface) == 0 as c_int;
    }

    fn unlock(&self) -> bool {
        return ll::video::SDL_UnlockSurface(self.raw_surface) == 0 as c_int;
    }

    fn blit_surface_rect(&self, src: &Surface, srcrect: &Rect, dstrect: &Rect) -> bool {
        let res = ll::video::SDL_UpperBlit(src.raw_surface, srcrect, self.raw_surface, dstrect);
        return res == 0 as c_int;
    }

    fn blit_surface(&self, src: &Surface) -> bool {
        let res = ll::video::SDL_UpperBlit(src.raw_surface, ptr::null(), self.raw_surface, ptr::null());
        return res == 0 as c_int;
    }

    fn fill_rect(&self, rect: &Rect, color: u32) -> bool {
        return ll::video::SDL_FillRect(self.raw_surface, rect, color) == 0 as c_int;
    }

    fn fill(&self, color: u32) -> bool {
        return ll::video::SDL_FillRect(self.raw_surface, ptr::null(), color) == 0 as c_int;
    }
}

pub impl Surface : Drop {
    pub fn finalize(&self) {
        ll::video::SDL_FreeSurface(self.raw_surface)
    }
}

//FIXME: This needs to be called multiple times on window resize, so Drop is going to do bad things, possibly. Test it out.
//Consider making videomode surfaces their own type, with a reset method?
pub fn set_video_mode(
    width: int,
    height: int,
    bitsperpixel: int,
    surface_flags: &[SurfaceFlag],
    video_mode_flags: &[VideoModeFlag]) -> Result<~Surface, ~str> {
    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });
    let flags = vec::foldl(flags, video_mode_flags, |flags, flag| {
        flags | *flag as u32
    });

    let raw_surface = ll::video::SDL_SetVideoMode(width as c_int, height as c_int, bitsperpixel as c_int, flags);

    if raw_surface == ptr::null() {
        Err(sdl::get_error())
    } else {
        Ok(~Surface{ raw_surface: raw_surface })
    }
}

pub fn load_bmp(file: &str) -> Result<~Surface, ~str> unsafe {
    str::as_buf(file, |buf, _len| {
        let buf = cast::reinterpret_cast(&buf);
        str::as_buf(~"rb", |rbbuf, _len| {
            let rbbuf = cast::reinterpret_cast(&rbbuf);
            let raw_surface = ll::video::SDL_LoadBMP_RW(ll::video::SDL_RWFromFile(buf, rbbuf), 1 as c_int);
            if raw_surface == ptr::null() {
                Err(sdl::get_error())
            } else {
                Ok(~Surface{ raw_surface: raw_surface })
            }
        })
    })
}

pub fn create_rgb_surface(
    surface_flags: &[SurfaceFlag],
    width: int, height: int, bits_per_pixel: int,
    rmask: u32, gmask: u32, bmask: u32, amask: u32) -> Result<~Surface, ~str> {

    let flags = vec::foldl(0u32, surface_flags, |flags, flag| {
        flags | *flag as u32
    });

    let raw_surface = ll::video::SDL_CreateRGBSurface(
        flags, width as c_int, height as c_int, bits_per_pixel as c_int,
        rmask, gmask, bmask, amask);
    if raw_surface == ptr::null() {
        Err(sdl::get_error())
    } else {
        Ok(~Surface{ raw_surface: raw_surface })
    }
}
<|endoftext|>


<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::fmt;
use crate::marker::{PhantomData, Unpin};

/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
/// customizes the behavior of the `RawWaker`.
///
/// [`Waker`]: struct.Waker.html
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &'static RawWakerVTable,
}

impl RawWaker {
    /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
    ///
    /// The `data` pointer can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this pointer will get passed to all functions that are part
    /// of the `vtable` as the first parameter.
    ///
    /// The `vtable` customizes the behavior of a `Waker` which gets created
    /// from a `RawWaker`. For each operation on the `Waker`, the associated
    /// function in the `vtable` of the underlying `RawWaker` will be called.
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
        RawWaker {
            data,
            vtable,
        }
    }
}

/// A virtual function pointer table (vtable) that specifies the behavior
/// of a [`RawWaker`].
///
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
/// The functions inside this struct are only intended be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    clone: unsafe fn(*const ()) -> RawWaker,

    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake: unsafe fn(*const ()),

    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake_by_ref: unsafe fn(*const ()),

    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    drop: unsafe fn(*const ()),
}

impl RawWakerVTable {
    /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
    /// `wake_by_ref`, and `drop` functions.
    ///
    /// # `clone`
    ///
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// # `wake`
    ///
    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// # `wake_by_ref`
    ///
    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// # `drop`
    ///
    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
    // without first consulting with T-Lang.
    //
    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
    #[rustc_allow_const_fn_ptr]
    pub const fn new(
        clone: unsafe fn(*const ()) -> RawWaker,
        wake: unsafe fn(*const ()),
        wake_by_ref: unsafe fn(*const ()),
        drop: unsafe fn(*const ()),
    ) -> Self {
        Self {
            clone,
            wake,
            wake_by_ref,
            drop,
        }
    }
}

/// The `Context` of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
    waker: &'a Waker,
    // Ensure we future-proof against variance changes by forcing
    // the lifetime to be invariant (argument-position lifetimes
    // are contravariant while return-position lifetimes are
    // covariant).
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    /// Create a new `Context` from a `&Waker`.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
        Context {
            waker,
            _marker: PhantomData,
        }
    }

    /// Returns a reference to the `Waker` for the current task.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Context<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context")
            .field("waker", &self.waker)
            .finish()
    }
}

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`trait@Send`], and [`trait@Sync`].
///
/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
    waker: RawWaker,
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Unpin for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Send for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Sync for Waker {}

impl Waker {
    /// Wake up the task associated with this `Waker`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

    /// Wake up the task associated with this `Waker` without consuming the `Waker`.
    ///
    /// This is similar to `wake`, but may be slightly less efficient in the case
    /// where an owned `Waker` is available. This method should be preferred to
    /// calling `waker.clone().wake()`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake_by_ref(&self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.

        // SAFETY: see `wake`
        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
    }

    /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.waker == other.waker
    }

    /// Creates a new `Waker` from [`RawWaker`].
    ///
    /// The behavior of the returned `Waker` is undefined if the contract defined
    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
    /// Therefore this method is unsafe.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    /// [`RawWakerVTable`]: struct.RawWakerVTable.html
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub unsafe fn from_raw(waker: RawWaker) -> Waker {
        Waker {
            waker,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        Waker {
            // SAFETY: This is safe because `Waker::from_raw` is the only way
            // to initialize `clone` and `data` requiring the user to acknowledge
            // that the contract of [`RawWaker`] is upheld.
            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `drop` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (self.waker.vtable.drop)(self.waker.data) }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
        f.debug_struct("Waker")
            .field("data", &self.waker.data)
            .field("vtable", &vtable_ptr)
            .finish()
    }
}
<commit_msg>Fix typo<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::fmt;
use crate::marker::{PhantomData, Unpin};

/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
/// customizes the behavior of the `RawWaker`.
///
/// [`Waker`]: struct.Waker.html
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &'static RawWakerVTable,
}

impl RawWaker {
    /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
    ///
    /// The `data` pointer can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this pointer will get passed to all functions that are part
    /// of the `vtable` as the first parameter.
    ///
    /// The `vtable` customizes the behavior of a `Waker` which gets created
    /// from a `RawWaker`. For each operation on the `Waker`, the associated
    /// function in the `vtable` of the underlying `RawWaker` will be called.
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
        RawWaker {
            data,
            vtable,
        }
    }
}

/// A virtual function pointer table (vtable) that specifies the behavior
/// of a [`RawWaker`].
///
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
/// The functions inside this struct are only intended be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    clone: unsafe fn(*const ()) -> RawWaker,

    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake: unsafe fn(*const ()),

    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake_by_ref: unsafe fn(*const ()),

    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    drop: unsafe fn(*const ()),
}

impl RawWakerVTable {
    /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
    /// `wake_by_ref`, and `drop` functions.
    ///
    /// # `clone`
    ///
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// # `wake`
    ///
    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// # `wake_by_ref`
    ///
    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// # `drop`
    ///
    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
    // without first consulting with T-Lang.
    //
    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
    #[rustc_allow_const_fn_ptr]
    pub const fn new(
        clone: unsafe fn(*const ()) -> RawWaker,
        wake: unsafe fn(*const ()),
        wake_by_ref: unsafe fn(*const ()),
        drop: unsafe fn(*const ()),
    ) -> Self {
        Self {
            clone,
            wake,
            wake_by_ref,
            drop,
        }
    }
}

/// The `Context` of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
    waker: &'a Waker,
    // Ensure we future-proof against variance changes by forcing
    // the lifetime to be invariant (argument-position lifetimes
    // are contravariant while return-position lifetimes are
    // covariant).
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    /// Create a new `Context` from a `&Waker`.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
        Context {
            waker,
            _marker: PhantomData,
        }
    }

    /// Returns a reference to the `Waker` for the current task.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Context<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context")
            .field("waker", &self.waker)
            .finish()
    }
}

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
///
/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
    waker: RawWaker,
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Unpin for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Send for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Sync for Waker {}

impl Waker {
    /// Wake up the task associated with this `Waker`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

    /// Wake up the task associated with this `Waker` without consuming the `Waker`.
    ///
    /// This is similar to `wake`, but may be slightly less efficient in the case
    /// where an owned `Waker` is available. This method should be preferred to
    /// calling `waker.clone().wake()`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake_by_ref(&self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.

        // SAFETY: see `wake`
        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
    }

    /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.waker == other.waker
    }

    /// Creates a new `Waker` from [`RawWaker`].
    ///
    /// The behavior of the returned `Waker` is undefined if the contract defined
    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
    /// Therefore this method is unsafe.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    /// [`RawWakerVTable`]: struct.RawWakerVTable.html
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub unsafe fn from_raw(waker: RawWaker) -> Waker {
        Waker {
            waker,
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        Waker {
            // SAFETY: This is safe because `Waker::from_raw` is the only way
            // to initialize `clone` and `data` requiring the user to acknowledge
            // that the contract of [`RawWaker`] is upheld.
            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `drop` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (self.waker.vtable.drop)(self.waker.data) }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
        f.debug_struct("Waker")
            .field("data", &self.waker.data)
            .field("vtable", &vtable_ptr)
            .finish()
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use std::libc::{c_int, c_char};
use sdl2::surface::ll::SDL_Surface;
use sdl2::rwops::ll::SDL_RWops;
use sdl2::render::ll::SDL_Texture;
use sdl2::render::ll::SDL_Renderer;

pub type IMG_InitFlags = c_int;
pub static IMG_INIT_JPG: IMG_InitFlags = 0x00000001;
pub static IMG_INIT_PNG: IMG_InitFlags = 0x00000002;
pub static IMG_INIT_TIF: IMG_InitFlags = 0x00000004;
pub static IMG_INIT_WEBP: IMG_InitFlags = 0x00000008;

pub struct SDL_version {
    major: int,
    minor: int,
    patch: int,
}

extern "C" {

// This function gets the version of the dynamically linked SDL_image library.
pub fn IMG_Linked_Version() -> *SDL_version;

// Loads dynamic libraries and prepares them for use.  Flags should be
// one or more flags from IMG_InitFlags OR'd together.
// It returns the flags successfully initialized, or 0 on failure.
pub fn IMG_Init(flags: c_int) -> c_int;

// Unloads libraries loaded with IMG_Init
pub fn IMG_Quit();

// Load an image from an SDL data source.
// The 'type' may be one of: "BMP", "GIF", "PNG", etc.
// If the image format supports a transparent pixel, SDL will set the
// colorkey for the surface.  You can enable RLE acceleration on the
// surface afterwards by calling:
//  SDL_SetColorKey(image, SDL_RLEACCEL, image->format->colorkey);
pub fn IMG_LoadTyped_RW(src: *SDL_RWops, freesrc: c_int,
                        fmt: *c_char) -> *SDL_Surface;

// Convenience functions
pub fn IMG_Load(file: *c_char) -> *SDL_Surface;
pub fn IMG_Load_RW(src: *SDL_RWops, freesrc: c_int) -> *SDL_Surface;

// Load an image directly into a render texture.
// Requires SDL2
pub fn IMG_LoadTexture(renderer: *SDL_Renderer,
                       file: *c_char) -> *SDL_Texture;
pub fn IMG_LoadTexture_RW(renderer: *SDL_Renderer, src: *SDL_RWops,
                          freesrc: c_int) -> *SDL_Texture;
pub fn IMG_LoadTextureTyped_RW(renderer: *SDL_Renderer, src: *SDL_RWops,
                               freesrc: c_int, fmt: *c_char) -> *SDL_Texture;

// Functions to detect a file type, given a seekable source
pub fn IMG_isICO(src: *SDL_RWops) -> c_int;
pub fn IMG_isCUR(src: *SDL_RWops) -> c_int;
pub fn IMG_isBMP(src: *SDL_RWops) -> c_int;
pub fn IMG_isGIF(src: *SDL_RWops) -> c_int;
pub fn IMG_isJPG(src: *SDL_RWops) -> c_int;
pub fn IMG_isLBM(src: *SDL_RWops) -> c_int;
pub fn IMG_isPCX(src: *SDL_RWops) -> c_int;
pub fn IMG_isPNG(src: *SDL_RWops) -> c_int;
pub fn IMG_isPNM(src: *SDL_RWops) -> c_int;
pub fn IMG_isTIF(src: *SDL_RWops) -> c_int;
pub fn IMG_isXCF(src: *SDL_RWops) -> c_int;
pub fn IMG_isXPM(src: *SDL_RWops) -> c_int;
pub fn IMG_isXV(src: *SDL_RWops) -> c_int;
pub fn IMG_isWEBP(src: *SDL_RWops) -> c_int;

// Individual loading functions
pub fn IMG_LoadICO_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadCUR_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadBMP_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadGIF_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadJPG_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadLBM_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadPCX_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadPNG_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadPNM_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadTGA_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadTIF_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadXCF_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadXPM_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadXV_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadWEBP_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_ReadXPMFromArray(xpm: **c_char) -> *SDL_Surface;

// Individual saving functions
pub fn IMG_SavePNG(surface: *SDL_Surface, file: *c_char) -> c_int;
pub fn IMG_SavePNG_RW(surface: *SDL_Surface, dst: *SDL_RWops,
                      freedst: c_int) -> c_int;

}   // extern "C"
<commit_msg>fix compile error: struct field default now private<commit_after>extern crate sdl2;

use std::libc::{c_int, c_char};
use sdl2::surface::ll::SDL_Surface;
use sdl2::rwops::ll::SDL_RWops;
use sdl2::render::ll::SDL_Texture;
use sdl2::render::ll::SDL_Renderer;

pub type IMG_InitFlags = c_int;
pub static IMG_INIT_JPG: IMG_InitFlags = 0x00000001;
pub static IMG_INIT_PNG: IMG_InitFlags = 0x00000002;
pub static IMG_INIT_TIF: IMG_InitFlags = 0x00000004;
pub static IMG_INIT_WEBP: IMG_InitFlags = 0x00000008;

pub struct SDL_version {
    pub major: int,
    pub minor: int,
    pub patch: int,
}

extern "C" {

// This function gets the version of the dynamically linked SDL_image library.
pub fn IMG_Linked_Version() -> *SDL_version;

// Loads dynamic libraries and prepares them for use.  Flags should be
// one or more flags from IMG_InitFlags OR'd together.
// It returns the flags successfully initialized, or 0 on failure.
pub fn IMG_Init(flags: c_int) -> c_int;

// Unloads libraries loaded with IMG_Init
pub fn IMG_Quit();

// Load an image from an SDL data source.
// The 'type' may be one of: "BMP", "GIF", "PNG", etc.
// If the image format supports a transparent pixel, SDL will set the
// colorkey for the surface.  You can enable RLE acceleration on the
// surface afterwards by calling:
//  SDL_SetColorKey(image, SDL_RLEACCEL, image->format->colorkey);
pub fn IMG_LoadTyped_RW(src: *SDL_RWops, freesrc: c_int,
                        fmt: *c_char) -> *SDL_Surface;

// Convenience functions
pub fn IMG_Load(file: *c_char) -> *SDL_Surface;
pub fn IMG_Load_RW(src: *SDL_RWops, freesrc: c_int) -> *SDL_Surface;

// Load an image directly into a render texture.
// Requires SDL2
pub fn IMG_LoadTexture(renderer: *SDL_Renderer,
                       file: *c_char) -> *SDL_Texture;
pub fn IMG_LoadTexture_RW(renderer: *SDL_Renderer, src: *SDL_RWops,
                          freesrc: c_int) -> *SDL_Texture;
pub fn IMG_LoadTextureTyped_RW(renderer: *SDL_Renderer, src: *SDL_RWops,
                               freesrc: c_int, fmt: *c_char) -> *SDL_Texture;

// Functions to detect a file type, given a seekable source
pub fn IMG_isICO(src: *SDL_RWops) -> c_int;
pub fn IMG_isCUR(src: *SDL_RWops) -> c_int;
pub fn IMG_isBMP(src: *SDL_RWops) -> c_int;
pub fn IMG_isGIF(src: *SDL_RWops) -> c_int;
pub fn IMG_isJPG(src: *SDL_RWops) -> c_int;
pub fn IMG_isLBM(src: *SDL_RWops) -> c_int;
pub fn IMG_isPCX(src: *SDL_RWops) -> c_int;
pub fn IMG_isPNG(src: *SDL_RWops) -> c_int;
pub fn IMG_isPNM(src: *SDL_RWops) -> c_int;
pub fn IMG_isTIF(src: *SDL_RWops) -> c_int;
pub fn IMG_isXCF(src: *SDL_RWops) -> c_int;
pub fn IMG_isXPM(src: *SDL_RWops) -> c_int;
pub fn IMG_isXV(src: *SDL_RWops) -> c_int;
pub fn IMG_isWEBP(src: *SDL_RWops) -> c_int;

// Individual loading functions
pub fn IMG_LoadICO_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadCUR_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadBMP_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadGIF_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadJPG_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadLBM_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadPCX_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadPNG_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadPNM_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadTGA_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadTIF_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadXCF_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadXPM_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadXV_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_LoadWEBP_RW(src: *SDL_RWops) -> *SDL_Surface;
pub fn IMG_ReadXPMFromArray(xpm: **c_char) -> *SDL_Surface;

// Individual saving functions
pub fn IMG_SavePNG(surface: *SDL_Surface, file: *c_char) -> c_int;
pub fn IMG_SavePNG_RW(surface: *SDL_Surface, dst: *SDL_RWops,
                      freedst: c_int) -> c_int;

}   // extern "C"
<|endoftext|>


<commit_before>
mod with_macro;

pub use self::with_macro::*;

macro_rules! print {
    ( $( $x:expr ),* ) => {
        {
            $(
                $x.print();
            )*
        }
    };
}

#[cfg(test)]
pub mod tests {
    use super::*;

    pub fn run_all() { // FIXME: how to use it via make?
        integration1();
    }

    fn integration1() {
        // this test should be checked manually.
        // correct output is:
        // This is [12, -154, 0] in octal: [14, -232, 0] and in hex: [c, -9a, 0].

        let x = [12, -154, 0];
        let msg1 = "This is "; // FIXME
        let msg2 = " in octal: ";
        let msg3 = " and in hex: ";
        let msg4 = ".\n";
        print!(msg1, x, msg2, octal(&x), msg3, hex(&x), msg4);
    }
}
<commit_msg>FIXME added<commit_after>
// FIXME: It all should be in another module (not connected with serial port)
// FIXME: And must be able to write in different places (for example: in char buffer)
// FIXME: i.e. implement trait similar to `core::fmt::Write`
// FIXME: or fix &str arguments and use `core::fmt::Write`
// FIXME: but don't delete this code!! It's really cool :)

mod with_macro;

pub use self::with_macro::*;

macro_rules! print {
    ( $( $x:expr ),* ) => {
        {
            $(
                $x.print();
            )*
        }
    };
}

#[cfg(test)]
pub mod tests {
    use super::*;

    pub fn run_all() { // FIXME: how to use it via make?
        integration1();
    }

    fn integration1() {
        // this test should be checked manually.
        // correct output is:
        // This is [12, -154, 0] in octal: [14, -232, 0] and in hex: [c, -9a, 0].

        let x = [12, -154, 0];
        let msg1 = "This is "; // FIXME
        let msg2 = " in octal: ";
        let msg3 = " and in hex: ";
        let msg4 = ".\n";
        print!(msg1, x, msg2, octal(&x), msg3, hex(&x), msg4);
    }
}
<|endoftext|>


<commit_before>import std::map;
import std::map::hashmap;
import ast::*;
import print::pprust;
import ast_util::path_to_ident;
import ast_util::inlined_item_methods;
import diagnostic::span_handler;

enum path_elt { path_mod(ident), path_name(ident) }
type path = ~[path_elt];

/* FIXMEs that say "bad" are as per #2543 */
fn path_to_str_with_sep(p: path, sep: str) -> str {
    let strs = do vec::map(p) |e| {
        alt e {
          path_mod(s) { /* FIXME (#2543) */ copy *s }
          path_name(s) { /* FIXME (#2543) */ copy *s }
        }
    };
    str::connect(strs, sep)
}

fn path_ident_to_str(p: path, i: ident) -> str {
    if vec::is_empty(p) {
        /* FIXME (#2543) */ copy *i
    } else {
        #fmt["%s::%s", path_to_str(p), *i]
    }
}

fn path_to_str(p: path) -> str {
    path_to_str_with_sep(p, "::")
}

enum ast_node {
    node_item(@item, @path),
    node_foreign_item(@foreign_item, foreign_abi, @path),
    node_method(@method, def_id /* impl did */, @path /* path to the impl */),
    node_variant(variant, @item, @path),
    node_expr(@expr),
    node_export(@view_path, @path),
    // Locals are numbered, because the alias analysis needs to know in which
    // order they are introduced.
    node_arg(arg, uint),
    node_local(uint),
    // Constructor for a class
    // def_id is parent id
    node_ctor(ident, ~[ty_param], @class_ctor, def_id, @path),
    // Destructor for a class
    node_dtor(~[ty_param], @class_dtor, def_id, @path),
    node_block(blk),
}

type map = std::map::hashmap<node_id, ast_node>;
type ctx = {map: map, mut path: path,
            mut local_id: uint, diag: span_handler};
type vt = visit::vt<ctx>;

fn extend(cx: ctx, +elt: ident) -> @path {
    @(vec::append(cx.path, ~[path_name(elt)]))
}

fn mk_ast_map_visitor() -> vt {
    ret visit::mk_vt(@{
        visit_item: map_item,
        visit_expr: map_expr,
        visit_fn: map_fn,
        visit_local: map_local,
        visit_arm: map_arm,
        visit_view_item: map_view_item,
        visit_block: map_block
        with *visit::default_visitor()
    });
}

fn map_crate(diag: span_handler, c: crate) -> map {
    let cx = {map: std::map::int_hash(),
              mut path: ~[],
              mut local_id: 0u,
              diag: diag};
    visit::visit_crate(c, cx, mk_ast_map_visitor());
    ret cx.map;
}

// Used for items loaded from external crate that are being inlined into this
// crate.  The `path` should be the path to the item but should not include
// the item itself.
fn map_decoded_item(diag: span_handler,
                    map: map, +path: path, ii: inlined_item) {
    // I believe it is ok for the local IDs of inlined items from other crates
    // to overlap with the local ids from this crate, so just generate the ids
    // starting from 0.  (In particular, I think these ids are only used in
    // alias analysis, which we will not be running on the inlined items, and
    // even if we did I think it only needs an ordering between local
    // variables that are simultaneously in scope).
    let cx = {map: map,
              mut path: /* FIXME (#2543) */ copy path,
              mut local_id: 0u,
              diag: diag};
    let v = mk_ast_map_visitor();

    // methods get added to the AST map when their impl is visited.  Since we
    // don't decode and instantiate the impl, but just the method, we have to
    // add it to the table now:
    alt ii {
      ii_item(*) | ii_ctor(*) | ii_dtor(*) { /* fallthrough */ }
      ii_foreign(i) {
        cx.map.insert(i.id, node_foreign_item(i, foreign_abi_rust_intrinsic,
                                             @path));
      }
      ii_method(impl_did, m) {
        map_method(impl_did, @path, m, cx);
      }
    }

    // visit the item / method contents and add those to the map:
    ii.accept(cx, v);
}

fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
          sp: codemap::span, id: node_id, cx: ctx, v: vt) {
    for decl.inputs.each |a| {
        cx.map.insert(a.id,
                      node_arg(/* FIXME (#2543) */
                          copy a, cx.local_id));
        cx.local_id += 1u;
    }
    alt fk {
      visit::fk_ctor(nm, tps, self_id, parent_id) {
          let ct = @{node: {id: id,
                            self_id: self_id,
                            dec: /* FIXME (#2543) */ copy decl,
                            body: /* FIXME (#2543) */ copy body},
                    span: sp};
          cx.map.insert(id, node_ctor(/* FIXME (#2543) */ copy nm,
                                      /* FIXME (#2543) */ copy tps,
                                      ct, parent_id,
                                      @/* FIXME (#2543) */ copy cx.path));
       }
      visit::fk_dtor(tps, self_id, parent_id) {
          let dt = @{node: {id: id, self_id: self_id,
                     body: /* FIXME (#2543) */ copy body}, span: sp};
          cx.map.insert(id, node_dtor(/* FIXME (#2543) */ copy tps, dt,
                                      parent_id,
                                      @/* FIXME (#2543) */ copy cx.path));
       }

       _ {}
    }
    visit::visit_fn(fk, decl, body, sp, id, cx, v);
}

fn map_block(b: blk, cx: ctx, v: vt) {
    cx.map.insert(b.node.id, node_block(/* FIXME (#2543) */ copy b));
    visit::visit_block(b, cx, v);
}

fn number_pat(cx: ctx, pat: @pat) {
    do ast_util::walk_pat(pat) |p| {
        alt p.node {
          pat_ident(_, _) {
            cx.map.insert(p.id, node_local(cx.local_id));
            cx.local_id += 1u;
          }
          _ {}
        }
    };
}

fn map_local(loc: @local, cx: ctx, v: vt) {
    number_pat(cx, loc.node.pat);
    visit::visit_local(loc, cx, v);
}

fn map_arm(arm: arm, cx: ctx, v: vt) {
    number_pat(cx, arm.pats[0]);
    visit::visit_arm(arm, cx, v);
}

fn map_method(impl_did: def_id, impl_path: @path,
              m: @method, cx: ctx) {
    cx.map.insert(m.id, node_method(m, impl_did, impl_path));
    cx.map.insert(m.self_id, node_local(cx.local_id));
    cx.local_id += 1u;
}

fn map_item(i: @item, cx: ctx, v: vt) {
    let item_path = @/* FIXME (#2543) */ copy cx.path;
    cx.map.insert(i.id, node_item(i, item_path));
    alt i.node {
      item_impl(_, _, _, _, ms) {
        let impl_did = ast_util::local_def(i.id);
        for ms.each |m| {
            map_method(impl_did, extend(cx, i.ident), m,
                       cx);
        }
      }
      item_enum(vs, _, _) {
        for vs.each |v| {
            cx.map.insert(v.node.id, node_variant(
                /* FIXME (#2543) */ copy v, i,
                extend(cx, i.ident)));
        }
      }
      item_foreign_mod(nm) {
        let abi = alt attr::foreign_abi(i.attrs) {
          either::left(msg) { cx.diag.span_fatal(i.span, msg); }
          either::right(abi) { abi }
        };
        for nm.items.each |nitem| {
            cx.map.insert(nitem.id,
                          node_foreign_item(nitem, abi,
                                           /* FIXME (#2543) */
                                           @copy cx.path));
        }
      }
      item_class(tps, ifces, items, ctor, dtor, _) {
          let (_, ms) = ast_util::split_class_items(items);
          // Map iface refs to their parent classes. This is
          // so we can find the self_ty
          do vec::iter(ifces) |p| { cx.map.insert(p.id,
                                  node_item(i, item_path)); };
          let d_id = ast_util::local_def(i.id);
          let p = extend(cx, i.ident);
           // only need to handle methods
          do vec::iter(ms) |m| { map_method(d_id, p, m, cx); }
      }
      _ { }
    }
    alt i.node {
      item_mod(_) | item_foreign_mod(_) {
        vec::push(cx.path, path_mod(i.ident));
      }
      _ { vec::push(cx.path, path_name(i.ident)); }
    }
    visit::visit_item(i, cx, v);
    vec::pop(cx.path);
}

fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
    alt vi.node {
      view_item_export(vps) {
        for vps.each |vp| {
            let (id, name) = alt vp.node {
              view_path_simple(nm, _, id) {
                (id, /* FIXME (#2543) */ copy nm)
              }
              view_path_glob(pth, id) | view_path_list(pth, _, id) {
                (id, path_to_ident(pth))
              }
            };
            cx.map.insert(id, node_export(vp, extend(cx, name)));
        }
      }
      _ {}
    }
}

fn map_expr(ex: @expr, cx: ctx, v: vt) {
    cx.map.insert(ex.id, node_expr(ex));
    visit::visit_expr(ex, cx, v);
}

fn node_id_to_str(map: map, id: node_id) -> str {
    alt map.find(id) {
      none {
        #fmt["unknown node (id=%d)", id]
      }
      some(node_item(item, path)) {
        #fmt["item %s (id=%?)", path_ident_to_str(*path, item.ident), id]
      }
      some(node_foreign_item(item, abi, path)) {
        #fmt["foreign item %s with abi %? (id=%?)",
             path_ident_to_str(*path, item.ident), abi, id]
      }
      some(node_method(m, impl_did, path)) {
        #fmt["method %s in %s (id=%?)",
             *m.ident, path_to_str(*path), id]
      }
      some(node_variant(variant, def_id, path)) {
        #fmt["variant %s in %s (id=%?)",
             *variant.node.name, path_to_str(*path), id]
      }
      some(node_expr(expr)) {
        #fmt["expr %s (id=%?)",
             pprust::expr_to_str(expr), id]
      }
      // FIXMEs are as per #2410
      some(node_export(_, path)) {
        #fmt["export %s (id=%?)", // add more info here
             path_to_str(*path), id]
      }
      some(node_arg(_, _)) { // add more info here
        #fmt["arg (id=%?)", id]
      }
      some(node_local(_)) { // add more info here
        #fmt["local (id=%?)", id]
      }
      some(node_ctor(*)) { // add more info here
        #fmt["node_ctor (id=%?)", id]
      }
      some(node_dtor(*)) { // add more info here
        #fmt["node_dtor (id=%?)", id]
      }
      some(node_block(_)) {
        #fmt["block"]
      }
    }
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>syntax: Add native module names correctly when building up the paths in the AST map<commit_after>import std::map;
import std::map::hashmap;
import ast::*;
import print::pprust;
import ast_util::path_to_ident;
import ast_util::inlined_item_methods;
import diagnostic::span_handler;

enum path_elt { path_mod(ident), path_name(ident) }
type path = ~[path_elt];

/* FIXMEs that say "bad" are as per #2543 */
fn path_to_str_with_sep(p: path, sep: str) -> str {
    let strs = do vec::map(p) |e| {
        alt e {
          path_mod(s) { /* FIXME (#2543) */ copy *s }
          path_name(s) { /* FIXME (#2543) */ copy *s }
        }
    };
    str::connect(strs, sep)
}

fn path_ident_to_str(p: path, i: ident) -> str {
    if vec::is_empty(p) {
        /* FIXME (#2543) */ copy *i
    } else {
        #fmt["%s::%s", path_to_str(p), *i]
    }
}

fn path_to_str(p: path) -> str {
    path_to_str_with_sep(p, "::")
}

enum ast_node {
    node_item(@item, @path),
    node_foreign_item(@foreign_item, foreign_abi, @path),
    node_method(@method, def_id /* impl did */, @path /* path to the impl */),
    node_variant(variant, @item, @path),
    node_expr(@expr),
    node_export(@view_path, @path),
    // Locals are numbered, because the alias analysis needs to know in which
    // order they are introduced.
    node_arg(arg, uint),
    node_local(uint),
    // Constructor for a class
    // def_id is parent id
    node_ctor(ident, ~[ty_param], @class_ctor, def_id, @path),
    // Destructor for a class
    node_dtor(~[ty_param], @class_dtor, def_id, @path),
    node_block(blk),
}

type map = std::map::hashmap<node_id, ast_node>;
type ctx = {map: map, mut path: path,
            mut local_id: uint, diag: span_handler};
type vt = visit::vt<ctx>;

fn extend(cx: ctx, +elt: ident) -> @path {
    @(vec::append(cx.path, ~[path_name(elt)]))
}

fn mk_ast_map_visitor() -> vt {
    ret visit::mk_vt(@{
        visit_item: map_item,
        visit_expr: map_expr,
        visit_fn: map_fn,
        visit_local: map_local,
        visit_arm: map_arm,
        visit_view_item: map_view_item,
        visit_block: map_block
        with *visit::default_visitor()
    });
}

fn map_crate(diag: span_handler, c: crate) -> map {
    let cx = {map: std::map::int_hash(),
              mut path: ~[],
              mut local_id: 0u,
              diag: diag};
    visit::visit_crate(c, cx, mk_ast_map_visitor());
    ret cx.map;
}

// Used for items loaded from external crate that are being inlined into this
// crate.  The `path` should be the path to the item but should not include
// the item itself.
fn map_decoded_item(diag: span_handler,
                    map: map, +path: path, ii: inlined_item) {
    // I believe it is ok for the local IDs of inlined items from other crates
    // to overlap with the local ids from this crate, so just generate the ids
    // starting from 0.  (In particular, I think these ids are only used in
    // alias analysis, which we will not be running on the inlined items, and
    // even if we did I think it only needs an ordering between local
    // variables that are simultaneously in scope).
    let cx = {map: map,
              mut path: /* FIXME (#2543) */ copy path,
              mut local_id: 0u,
              diag: diag};
    let v = mk_ast_map_visitor();

    // methods get added to the AST map when their impl is visited.  Since we
    // don't decode and instantiate the impl, but just the method, we have to
    // add it to the table now:
    alt ii {
      ii_item(*) | ii_ctor(*) | ii_dtor(*) { /* fallthrough */ }
      ii_foreign(i) {
        cx.map.insert(i.id, node_foreign_item(i, foreign_abi_rust_intrinsic,
                                             @path));
      }
      ii_method(impl_did, m) {
        map_method(impl_did, @path, m, cx);
      }
    }

    // visit the item / method contents and add those to the map:
    ii.accept(cx, v);
}

fn map_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
          sp: codemap::span, id: node_id, cx: ctx, v: vt) {
    for decl.inputs.each |a| {
        cx.map.insert(a.id,
                      node_arg(/* FIXME (#2543) */
                          copy a, cx.local_id));
        cx.local_id += 1u;
    }
    alt fk {
      visit::fk_ctor(nm, tps, self_id, parent_id) {
          let ct = @{node: {id: id,
                            self_id: self_id,
                            dec: /* FIXME (#2543) */ copy decl,
                            body: /* FIXME (#2543) */ copy body},
                    span: sp};
          cx.map.insert(id, node_ctor(/* FIXME (#2543) */ copy nm,
                                      /* FIXME (#2543) */ copy tps,
                                      ct, parent_id,
                                      @/* FIXME (#2543) */ copy cx.path));
       }
      visit::fk_dtor(tps, self_id, parent_id) {
          let dt = @{node: {id: id, self_id: self_id,
                     body: /* FIXME (#2543) */ copy body}, span: sp};
          cx.map.insert(id, node_dtor(/* FIXME (#2543) */ copy tps, dt,
                                      parent_id,
                                      @/* FIXME (#2543) */ copy cx.path));
       }

       _ {}
    }
    visit::visit_fn(fk, decl, body, sp, id, cx, v);
}

fn map_block(b: blk, cx: ctx, v: vt) {
    cx.map.insert(b.node.id, node_block(/* FIXME (#2543) */ copy b));
    visit::visit_block(b, cx, v);
}

fn number_pat(cx: ctx, pat: @pat) {
    do ast_util::walk_pat(pat) |p| {
        alt p.node {
          pat_ident(_, _) {
            cx.map.insert(p.id, node_local(cx.local_id));
            cx.local_id += 1u;
          }
          _ {}
        }
    };
}

fn map_local(loc: @local, cx: ctx, v: vt) {
    number_pat(cx, loc.node.pat);
    visit::visit_local(loc, cx, v);
}

fn map_arm(arm: arm, cx: ctx, v: vt) {
    number_pat(cx, arm.pats[0]);
    visit::visit_arm(arm, cx, v);
}

fn map_method(impl_did: def_id, impl_path: @path,
              m: @method, cx: ctx) {
    cx.map.insert(m.id, node_method(m, impl_did, impl_path));
    cx.map.insert(m.self_id, node_local(cx.local_id));
    cx.local_id += 1u;
}

fn map_item(i: @item, cx: ctx, v: vt) {
    let item_path = @/* FIXME (#2543) */ copy cx.path;
    cx.map.insert(i.id, node_item(i, item_path));
    alt i.node {
      item_impl(_, _, _, _, ms) {
        let impl_did = ast_util::local_def(i.id);
        for ms.each |m| {
            map_method(impl_did, extend(cx, i.ident), m,
                       cx);
        }
      }
      item_enum(vs, _, _) {
        for vs.each |v| {
            cx.map.insert(v.node.id, node_variant(
                /* FIXME (#2543) */ copy v, i,
                extend(cx, i.ident)));
        }
      }
      item_foreign_mod(nm) {
        let abi = alt attr::foreign_abi(i.attrs) {
          either::left(msg) { cx.diag.span_fatal(i.span, msg); }
          either::right(abi) { abi }
        };
        for nm.items.each |nitem| {
            cx.map.insert(nitem.id,
                          node_foreign_item(nitem, abi,
                                           /* FIXME (#2543) */
                                           extend(cx, i.ident)));
        }
      }
      item_class(tps, ifces, items, ctor, dtor, _) {
          let (_, ms) = ast_util::split_class_items(items);
          // Map iface refs to their parent classes. This is
          // so we can find the self_ty
          do vec::iter(ifces) |p| { cx.map.insert(p.id,
                                  node_item(i, item_path)); };
          let d_id = ast_util::local_def(i.id);
          let p = extend(cx, i.ident);
           // only need to handle methods
          do vec::iter(ms) |m| { map_method(d_id, p, m, cx); }
      }
      _ { }
    }
    alt i.node {
      item_mod(_) | item_foreign_mod(_) {
        vec::push(cx.path, path_mod(i.ident));
      }
      _ { vec::push(cx.path, path_name(i.ident)); }
    }
    visit::visit_item(i, cx, v);
    vec::pop(cx.path);
}

fn map_view_item(vi: @view_item, cx: ctx, _v: vt) {
    alt vi.node {
      view_item_export(vps) {
        for vps.each |vp| {
            let (id, name) = alt vp.node {
              view_path_simple(nm, _, id) {
                (id, /* FIXME (#2543) */ copy nm)
              }
              view_path_glob(pth, id) | view_path_list(pth, _, id) {
                (id, path_to_ident(pth))
              }
            };
            cx.map.insert(id, node_export(vp, extend(cx, name)));
        }
      }
      _ {}
    }
}

fn map_expr(ex: @expr, cx: ctx, v: vt) {
    cx.map.insert(ex.id, node_expr(ex));
    visit::visit_expr(ex, cx, v);
}

fn node_id_to_str(map: map, id: node_id) -> str {
    alt map.find(id) {
      none {
        #fmt["unknown node (id=%d)", id]
      }
      some(node_item(item, path)) {
        #fmt["item %s (id=%?)", path_ident_to_str(*path, item.ident), id]
      }
      some(node_foreign_item(item, abi, path)) {
        #fmt["foreign item %s with abi %? (id=%?)",
             path_ident_to_str(*path, item.ident), abi, id]
      }
      some(node_method(m, impl_did, path)) {
        #fmt["method %s in %s (id=%?)",
             *m.ident, path_to_str(*path), id]
      }
      some(node_variant(variant, def_id, path)) {
        #fmt["variant %s in %s (id=%?)",
             *variant.node.name, path_to_str(*path), id]
      }
      some(node_expr(expr)) {
        #fmt["expr %s (id=%?)",
             pprust::expr_to_str(expr), id]
      }
      // FIXMEs are as per #2410
      some(node_export(_, path)) {
        #fmt["export %s (id=%?)", // add more info here
             path_to_str(*path), id]
      }
      some(node_arg(_, _)) { // add more info here
        #fmt["arg (id=%?)", id]
      }
      some(node_local(_)) { // add more info here
        #fmt["local (id=%?)", id]
      }
      some(node_ctor(*)) { // add more info here
        #fmt["node_ctor (id=%?)", id]
      }
      some(node_dtor(*)) { // add more info here
        #fmt["node_dtor (id=%?)", id]
      }
      some(node_block(_)) {
        #fmt["block"]
      }
    }
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

impl<'a> Page<'a> {
    crate fn get_static_root_path(&self) -> &str {
        self.static_root_path.unwrap_or(self.root_path)
    }
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.get_static_root_path();
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" id=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<commit_msg>Add missing <title> in redirection page <commit_after>use std::path::PathBuf;

use rustc_data_structures::fx::FxHashMap;

use crate::externalfiles::ExternalHtml;
use crate::html::escape::Escape;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};

#[derive(Clone)]
crate struct Layout {
    crate logo: String,
    crate favicon: String,
    crate external_html: ExternalHtml,
    crate default_settings: FxHashMap<String, String>,
    crate krate: String,
    /// The given user css file which allow to customize the generated
    /// documentation theme.
    crate css_file_extension: Option<PathBuf>,
    /// If false, the `select` element to have search filtering by crates on rendered docs
    /// won't be generated.
    crate generate_search_filter: bool,
}

crate struct Page<'a> {
    crate title: &'a str,
    crate css_class: &'a str,
    crate root_path: &'a str,
    crate static_root_path: Option<&'a str>,
    crate description: &'a str,
    crate keywords: &'a str,
    crate resource_suffix: &'a str,
    crate extra_scripts: &'a [&'a str],
    crate static_extra_scripts: &'a [&'a str],
}

impl<'a> Page<'a> {
    crate fn get_static_root_path(&self) -> &str {
        self.static_root_path.unwrap_or(self.root_path)
    }
}

crate fn render<T: Print, S: Print>(
    layout: &Layout,
    page: &Page<'_>,
    sidebar: S,
    t: T,
    style_files: &[StylePath],
) -> String {
    let static_root_path = page.get_static_root_path();
    format!(
        "<!DOCTYPE html>\
\
\
    <meta charset=\"utf-8\">\
    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
    <meta name=\"generator\" content=\"rustdoc\">\
    <meta name=\"description\" content=\"{description}\">\
    <meta name=\"keywords\" content=\"{keywords}\">\
    <title>{title}</title>\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}normalize{suffix}.css\">\
    <link rel=\"stylesheet\" type=\"text/css\" href=\"{static_root_path}rustdoc{suffix}.css\" \
          id=\"mainThemeStyle\">\
    {style_files}\
    \
    \
    \
    <link rel=\"stylesheet\" href=\"{static_root_path}noscript{suffix}.css\">\
    {css_extension}\
    {favicon}\
    {in_header}\
    \
\
\
    \
    {before_content}\
    \

☰
\
        {logo}\
        {sidebar}\
    \

\
        <button id=\"theme-picker\" aria-label=\"Pick another theme!\" aria-haspopup=\"menu\">\
            \
        </button>\

\

\
    \
        <form class=\"search-form\">\

\

{filter_crates}\
                    <input class=\"search-input\" name=\"search\" \
                           disabled \
                           autocomplete=\"off\" \
                           spellcheck=\"false\" \
                           placeholder=\"Click or press ‘S’ to search, ‘?’ for more options…\" \
                           type=\"search\">\

\
                <button type=\"button\" id=\"help-button\">?</button>
                \
                    \
                \

\
        </form>\
    \

{content}
\

\
    {after_content}\

    \
    {extra_scripts}\
\
",
        css_extension = if layout.css_file_extension.is_some() {
            format!(
                "<link rel=\"stylesheet\" \
                       type=\"text/css\" \
                       href=\"{static_root_path}theme{suffix}.css\">",
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            String::new()
        },
        content = Buffer::html().to_display(t),
        static_root_path = static_root_path,
        root_path = page.root_path,
        css_class = page.css_class,
        logo = {
            if layout.logo.is_empty() {
                format!(
                    "\

\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    static_root_path = static_root_path,
                    suffix = page.resource_suffix
                )
            } else {
                format!(
                    "\

",
                    root = page.root_path,
                    path = ensure_trailing_slash(&layout.krate),
                    logo = layout.logo
                )
            }
        },
        title = page.title,
        description = page.description,
        keywords = page.keywords,
        favicon = if layout.favicon.is_empty() {
            format!(
                r##"<link rel="icon" type="image/svg+xml" href="{static_root_path}favicon{suffix}.svg">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-16x16{suffix}.png">
<link rel="alternate icon" type="image/png" href="{static_root_path}favicon-32x32{suffix}.png">"##,
                static_root_path = static_root_path,
                suffix = page.resource_suffix
            )
        } else {
            format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
        },
        in_header = layout.external_html.in_header,
        before_content = layout.external_html.before_content,
        after_content = layout.external_html.after_content,
        sidebar = Buffer::html().to_display(sidebar),
        krate = layout.krate,
        default_settings = layout
            .default_settings
            .iter()
            .map(|(k, v)| format!(r#" data-{}="{}""#, k.replace('-', "_"), Escape(v)))
            .collect::<String>(),
        style_files = style_files
            .iter()
            .filter_map(|t| {
                if let Some(stem) = t.path.file_stem() { Some((stem, t.disabled)) } else { None }
            })
            .filter_map(|t| {
                if let Some(path) = t.0.to_str() { Some((path, t.1)) } else { None }
            })
            .map(|t| format!(
                r#"<link rel="stylesheet" type="text/css" href="{}.css" {} {}>"#,
                Escape(&format!("{}{}{}", static_root_path, t.0, page.resource_suffix)),
                if t.1 { "disabled" } else { "" },
                if t.0 == "light" { "id=\"themeStyle\"" } else { "" }
            ))
            .collect::<String>(),
        suffix = page.resource_suffix,
        extra_scripts = page
            .static_extra_scripts
            .iter()
            .map(|e| {
                format!(
                    "",
                    static_root_path = static_root_path,
                    extra_script = e
                )
            })
            .chain(page.extra_scripts.iter().map(|e| {
                format!(
                    "",
                    root_path = page.root_path,
                    extra_script = e
                )
            }))
            .collect::<String>(),
        filter_crates = if layout.generate_search_filter {
            "<select id=\"crate-search\">\
                 <option value=\"All crates\">All crates</option>\
             </select>"
        } else {
            ""
        },
    )
}

crate fn redirect(url: &str) -> String {
    //

"##,
        url = url,
    )
}
<|endoftext|>