<commit_before>use std::collections::HashMap;
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Write};

use rustc::ty::layout::Size;

use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Debug)]
pub struct FileHandle {
    file: File,
}

pub struct FileHandler {
    handles: HashMap<i32, FileHandle>,
    low: i32,
}

impl Default for FileHandler {
    fn default() -> Self {
        FileHandler {
            handles: Default::default(),
            // 0, 1 and 2 are reserved for stdin, stdout and stderr.
            low: 3,
        }
    }
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn open(
        &mut self,
        path_op: OpTy<'tcx, Tag>,
        flag_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("open")?;

        let flag = this.read_scalar(flag_op)?.to_i32()?;

        let mut options = OpenOptions::new();

        let o_rdonly = this.eval_libc_i32("O_RDONLY")?;
        let o_wronly = this.eval_libc_i32("O_WRONLY")?;
        let o_rdwr = this.eval_libc_i32("O_RDWR")?;
        // The first two bits of the flag correspond to the access mode in linux, macOS and
        // windows. We need to check that in fact the access mode flags for the current platform
        // only use these two bits, otherwise we are in an unsupported platform and should error.
        if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
            throw_unsup_format!("Access mode flags on this platform are unsupported");
        }
        // Now we check the access mode
        let access_mode = flag & 0b11;

        if access_mode == o_rdonly {
            options.read(true);
        } else if access_mode == o_wronly {
            options.write(true);
        } else if access_mode == o_rdwr {
            options.read(true).write(true);
        } else {
            throw_unsup_format!("Unsupported access mode {:#x}", access_mode);
        }
        // We need to check that there aren't unsupported options in `flag`. For this we try to
        // reproduce the content of `flag` in the `mirror` variable using only the supported
        // options.
        let mut mirror = access_mode;

        let o_append = this.eval_libc_i32("O_APPEND")?;
        if flag & o_append != 0 {
            options.append(true);
            mirror |= o_append;
        }
        let o_trunc = this.eval_libc_i32("O_TRUNC")?;
        if flag & o_trunc != 0 {
            options.truncate(true);
            mirror |= o_trunc;
        }
        let o_creat = this.eval_libc_i32("O_CREAT")?;
        if flag & o_creat != 0 {
            options.create(true);
            mirror |= o_creat;
        }
        let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?;
        if flag & o_cloexec != 0 {
            // We do not need to do anything for this flag because `std` already sets it.
            // (Technically we do not support *not* setting this flag, but we ignore that.)
            mirror |= o_cloexec;
        }
        // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
        // then we throw an error.
        if flag != mirror {
            throw_unsup_format!("unsupported flags {:#x}", flag & !mirror);
        }

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let fd = options.open(path).map(|file| {
            let mut fh = &mut this.machine.file_handler;
            fh.low += 1;
            fh.handles.insert(fh.low, FileHandle { file }).unwrap_none();
            fh.low
        });

        this.try_unwrap_io_result(fd)
    }

    fn fcntl(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        cmd_op: OpTy<'tcx, Tag>,
        _arg1_op: Option<OpTy<'tcx, Tag>>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("fcntl")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let cmd = this.read_scalar(cmd_op)?.to_i32()?;
        // We only support getting the flags for a descriptor.
        if cmd == this.eval_libc_i32("F_GETFD")? {
            // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
            // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
            // always sets this flag when opening a file. However we still need to check that the
            // file itself is open.
            if this.machine.file_handler.handles.contains_key(&fd) {
                Ok(this.eval_libc_i32("FD_CLOEXEC")?)
            } else {
                this.handle_not_found()
            }
        } else {
            throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd);
        }
    }

    fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("close")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;

        if let Some(handle) = this.machine.file_handler.handles.remove(&fd) {
            // `File::sync_all` does the checks that are done when closing a file. We do this to
            // to handle possible errors correctly.
            let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32));
            // Now we actually drop the handle.
            drop(handle);
            // And return the result.
            result
        } else {
            this.handle_not_found()
        }
    }

    fn read(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("read")?;

        let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
        // Reading zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            // We want to read at most `count` bytes
            let mut bytes = vec![0; count as usize];
            let result = handle.file.read(&mut bytes).map(|c| c as i64);
            let written_count = this.try_unwrap_io_result(result)?;
            // `try_unwrap_io_result` returns Ok(`-1`) if `result` is an error. There is no other
            // way of returning `-1` because the `Ok` variant of `result` contains the number of
            // written bytes, which is a possitive value.
            if written_count != -1 {
                // If reading to `bytes` did not fail, we write those bytes to the buffer.
                this.memory.write_bytes(buf, bytes)?;
            }
            Ok(written_count)
        } else {
            this.handle_not_found()
        }
    }

    fn write(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("write")?;

        let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
        // Writing zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?;
            let result = handle.file.write(&bytes).map(|c| c as i64);
            this.try_unwrap_io_result(result)
        } else {
            this.handle_not_found()
        }
    }

    fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("unlink")?;

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let result = remove_file(path).map(|_| 0);

        this.try_unwrap_io_result(result)
    }

    /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets
    /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
    /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
    /// types (like `read`, that returns an `i64`).
    fn handle_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
        let this = self.eval_context_mut();
        let ebadf = this.eval_libc("EBADF")?;
        this.set_last_error(ebadf)?;
        Ok((-1).into())
    }
}
<commit_msg>Simplify `read` logic<commit_after>use std::collections::HashMap;
use std::fs::{remove_file, File, OpenOptions};
use std::io::{Read, Write};

use rustc::ty::layout::Size;

use crate::stacked_borrows::Tag;
use crate::*;

#[derive(Debug)]
pub struct FileHandle {
    file: File,
}

pub struct FileHandler {
    handles: HashMap<i32, FileHandle>,
    low: i32,
}

impl Default for FileHandler {
    fn default() -> Self {
        FileHandler {
            handles: Default::default(),
            // 0, 1 and 2 are reserved for stdin, stdout and stderr.
            low: 3,
        }
    }
}

impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn open(
        &mut self,
        path_op: OpTy<'tcx, Tag>,
        flag_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("open")?;

        let flag = this.read_scalar(flag_op)?.to_i32()?;

        let mut options = OpenOptions::new();

        let o_rdonly = this.eval_libc_i32("O_RDONLY")?;
        let o_wronly = this.eval_libc_i32("O_WRONLY")?;
        let o_rdwr = this.eval_libc_i32("O_RDWR")?;
        // The first two bits of the flag correspond to the access mode in linux, macOS and
        // windows. We need to check that in fact the access mode flags for the current platform
        // only use these two bits, otherwise we are in an unsupported platform and should error.
        if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 {
            throw_unsup_format!("Access mode flags on this platform are unsupported");
        }
        // Now we check the access mode
        let access_mode = flag & 0b11;

        if access_mode == o_rdonly {
            options.read(true);
        } else if access_mode == o_wronly {
            options.write(true);
        } else if access_mode == o_rdwr {
            options.read(true).write(true);
        } else {
            throw_unsup_format!("Unsupported access mode {:#x}", access_mode);
        }
        // We need to check that there aren't unsupported options in `flag`. For this we try to
        // reproduce the content of `flag` in the `mirror` variable using only the supported
        // options.
        let mut mirror = access_mode;

        let o_append = this.eval_libc_i32("O_APPEND")?;
        if flag & o_append != 0 {
            options.append(true);
            mirror |= o_append;
        }
        let o_trunc = this.eval_libc_i32("O_TRUNC")?;
        if flag & o_trunc != 0 {
            options.truncate(true);
            mirror |= o_trunc;
        }
        let o_creat = this.eval_libc_i32("O_CREAT")?;
        if flag & o_creat != 0 {
            options.create(true);
            mirror |= o_creat;
        }
        let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?;
        if flag & o_cloexec != 0 {
            // We do not need to do anything for this flag because `std` already sets it.
            // (Technically we do not support *not* setting this flag, but we ignore that.)
            mirror |= o_cloexec;
        }
        // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`,
        // then we throw an error.
        if flag != mirror {
            throw_unsup_format!("unsupported flags {:#x}", flag & !mirror);
        }

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let fd = options.open(path).map(|file| {
            let mut fh = &mut this.machine.file_handler;
            fh.low += 1;
            fh.handles.insert(fh.low, FileHandle { file }).unwrap_none();
            fh.low
        });

        this.try_unwrap_io_result(fd)
    }

    fn fcntl(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        cmd_op: OpTy<'tcx, Tag>,
        _arg1_op: Option<OpTy<'tcx, Tag>>,
    ) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("fcntl")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let cmd = this.read_scalar(cmd_op)?.to_i32()?;
        // We only support getting the flags for a descriptor.
        if cmd == this.eval_libc_i32("F_GETFD")? {
            // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the
            // `FD_CLOEXEC` value without checking if the flag is set for the file because `std`
            // always sets this flag when opening a file. However we still need to check that the
            // file itself is open.
            if this.machine.file_handler.handles.contains_key(&fd) {
                Ok(this.eval_libc_i32("FD_CLOEXEC")?)
            } else {
                this.handle_not_found()
            }
        } else {
            throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd);
        }
    }

    fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("close")?;

        let fd = this.read_scalar(fd_op)?.to_i32()?;

        if let Some(handle) = this.machine.file_handler.handles.remove(&fd) {
            // `File::sync_all` does the checks that are done when closing a file. We do this to
            // to handle possible errors correctly.
            let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32));
            // Now we actually drop the handle.
            drop(handle);
            // And return the result.
            result
        } else {
            this.handle_not_found()
        }
    }

    fn read(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("read")?;

        let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
        // Reading zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            // We want to read at most `count` bytes
            let mut bytes = vec![0; count as usize];
            let result = handle.file.read(&mut bytes).map(|c| c as i64);
            // If reading to `bytes` did not fail, we write those bytes to the buffer.
            if result.is_ok() {
                this.memory.write_bytes(buf, bytes)?;
            }
            this.try_unwrap_io_result(result)
        } else {
            this.handle_not_found()
        }
    }

    fn write(
        &mut self,
        fd_op: OpTy<'tcx, Tag>,
        buf_op: OpTy<'tcx, Tag>,
        count_op: OpTy<'tcx, Tag>,
    ) -> InterpResult<'tcx, i64> {
        let this = self.eval_context_mut();

        this.check_no_isolation("write")?;

        let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?;
        // Writing zero bytes should not change `buf`.
        if count == 0 {
            return Ok(0);
        }
        let fd = this.read_scalar(fd_op)?.to_i32()?;
        let buf = this.read_scalar(buf_op)?.not_undef()?;

        if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) {
            let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?;
            let result = handle.file.write(&bytes).map(|c| c as i64);
            this.try_unwrap_io_result(result)
        } else {
            this.handle_not_found()
        }
    }

    fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> {
        let this = self.eval_context_mut();

        this.check_no_isolation("unlink")?;

        let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?;

        let result = remove_file(path).map(|_| 0);

        this.try_unwrap_io_result(result)
    }

    /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets
    /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses
    /// `T: From<i32>` instead of `i32` directly because some fs functions return different integer
    /// types (like `read`, that returns an `i64`).
    fn handle_not_found<T: From<i32>>(&mut self) -> InterpResult<'tcx, T> {
        let this = self.eval_context_mut();
        let ebadf = this.eval_libc("EBADF")?;
        this.set_last_error(ebadf)?;
        Ok((-1).into())
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

pub(crate) mod definitions;
pub(crate) mod fs;
pub(crate) mod io;
pub(crate) mod mtd;

use derive_more::{Display, Error, From};

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Display, Error, From)]
pub enum Error {
    Io(std::io::Error),
    Nix(nix::Error),
    Uncompress(compress_tools::Error),
    Process(easy_process::Error),
    StripPrefix(std::path::StripPrefixError),

    #[display("Target device does not exists")]
    DeviceDoesNotExist,

    #[display(fmt = "User doesn't have write permission on target device: {:?}", _0)]
    MissingWritePermission(#[error(not(source))] std::path::PathBuf),

    #[display("Not enough storage space for installation")]
    NotEnoughSpace,

    #[display(fmt = "'{}' not found on PATH", _0)]
    #[from(ignore)]
    ExecutableNotInPath(#[error(not(source))] String),
    #[display(fmt = "Unable to find Ubi Volume: {}" _0)]
    #[from(ignore)]
    NoUbiVolume(#[error(not(source))] String),
    #[display(fmt = "Unable to find match for mtd device: {}", _0)]
    #[from(ignore)]
    NoMtdDevice(#[error(not(source))] String),
}

/// Encode a bytes stream in hex
pub(crate) fn hex_encode(data: &[u8]) -> String {
    data.iter().map(|c| format!("{:02x}", c)).collect()
}

/// Get sha256sum hash from a byte stream
pub(crate) fn sha256sum(data: &[u8]) -> String {
    hex_encode(&openssl::sha::sha256(data))
}
<commit_msg>updatehub: utils: Use lowercase error messages<commit_after>// Copyright (C) 2019 O.S. Systems Sofware LTDA
//
// SPDX-License-Identifier: Apache-2.0

pub(crate) mod definitions;
pub(crate) mod fs;
pub(crate) mod io;
pub(crate) mod mtd;

use derive_more::{Display, Error, From};

pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Display, Error, From)]
pub enum Error {
    Io(std::io::Error),
    Nix(nix::Error),
    Uncompress(compress_tools::Error),
    Process(easy_process::Error),
    StripPrefix(std::path::StripPrefixError),

    #[display("target device does not exists")]
    DeviceDoesNotExist,

    #[display(fmt = "user doesn't have write permission on target device: {:?}", _0)]
    MissingWritePermission(#[error(not(source))] std::path::PathBuf),

    #[display("not enough storage space for installation")]
    NotEnoughSpace,

    #[display(fmt = "'{}' not found on PATH", _0)]
    #[from(ignore)]
    ExecutableNotInPath(#[error(not(source))] String),
    #[display(fmt = "unable to find Ubi Volume: {}" _0)]
    #[from(ignore)]
    NoUbiVolume(#[error(not(source))] String),
    #[display(fmt = "unable to find match for mtd device: {}", _0)]
    #[from(ignore)]
    NoMtdDevice(#[error(not(source))] String),
}

/// Encode a bytes stream in hex
pub(crate) fn hex_encode(data: &[u8]) -> String {
    data.iter().map(|c| format!("{:02x}", c)).collect()
}

/// Get sha256sum hash from a byte stream
pub(crate) fn sha256sum(data: &[u8]) -> String {
    hex_encode(&openssl::sha::sha256(data))
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

pub mod ruler;
pub mod canvas;
pub mod platform;

use std::path::Path;

use ::paint::{Point};
use ::layout::Layout;
use ::platform::Context;
use ::paint::Canvas as AkritiCanvas;
use ::draw::{Drawable, MeasureMode};

use self::platform::Platform;
use self::canvas::Canvas;

pub struct Snapshot {
    context: Context,
}

impl Snapshot {
    pub fn new(font: &str, snaps_dir: &str, font_size: f32) -> Snapshot {
        Snapshot {
            context: Context::new(Box::new(Platform::new(font)), font_size),
        }
    }

    pub fn snap_layout(&self, layout: &Layout, name: &str) {
        let layout = layout.layout(&self.context);

        let canvas: Canvas = self.context.platform().as_any().downcast_ref::<Platform>().unwrap()
            .new_canvas(layout.bounding_box().width(), layout.bounding_box().height());

        layout.draw(&canvas, &Point::new(0., 0.));

        canvas.as_any().downcast_ref::<Canvas>().unwrap().snapshot(Path::new("target")
            .join(format!("{}.png", name)).as_ref()).expect("Cannot snap");
    }

    pub fn snap_drawable(&self, drawable: &mut Drawable, width_mode: &MeasureMode,
                         height_mode: &MeasureMode, name: &str) {
        drawable.calculate(&self.context, width_mode, height_mode);

        let canvas: Canvas = self.context.platform().as_any().downcast_ref::<Platform>().unwrap()
            .new_canvas(drawable.bounding_box().width(), drawable.bounding_box().height());

        drawable.draw(&canvas, &Point::new(0., 0.));

        canvas.as_any().downcast_ref::<Canvas>().unwrap().snapshot(Path::new("target")
            .join(format!("{}.png", name)).as_ref()).expect("Cannot snap");
    }
}

impl Default for Snapshot {
    fn default() -> Snapshot {
        let root = env!("CARGO_MANIFEST_DIR");
        Snapshot::new(
            &format!("{}/src/test/assets/STIX2Math.otf", root),
            &format!("{}/target", root),
            64.
        )
    }
}<commit_msg>API for snapping elements<commit_after>/*
 * Copyright 2017 Sreejith Krishnan R
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

pub mod ruler;
pub mod canvas;
pub mod platform;

use std::path::Path;

use ::paint::{Point};
use ::layout::Layout;
use ::elements::{Element, InheritedProps};
use ::platform::Context;
use ::paint::Canvas as AkritiCanvas;
use ::draw::{Drawable, MeasureMode};

use self::platform::Platform;
use self::canvas::Canvas;

pub struct Snapshot {
    context: Context,
}

impl Snapshot {
    pub fn new(font: &str, snaps_dir: &str, font_size: f32) -> Snapshot {
        Snapshot {
            context: Context::new(Box::new(Platform::new(font)), font_size),
        }
    }

    pub fn snap_element(&self, element: &Element, name: &str) {
        let inherited_props = InheritedProps::default();
        let layout = element.layout(&self.context, None, &inherited_props, &None);
        self.snap_layout(layout.as_ref(), name);
    }

    pub fn snap_layout(&self, layout: &Layout, name: &str) {
        let layout = layout.layout(&self.context);

        let canvas: Canvas = self.context.platform().as_any().downcast_ref::<Platform>().unwrap()
            .new_canvas(layout.bounding_box().width(), layout.bounding_box().height());

        layout.draw(&canvas, &Point::new(0., 0.));

        canvas.as_any().downcast_ref::<Canvas>().unwrap().snapshot(Path::new("target")
            .join(format!("{}.png", name)).as_ref()).expect("Cannot snap");
    }

    pub fn snap_drawable(&self, drawable: &mut Drawable, width_mode: &MeasureMode,
                         height_mode: &MeasureMode, name: &str) {
        drawable.calculate(&self.context, width_mode, height_mode);

        let canvas: Canvas = self.context.platform().as_any().downcast_ref::<Platform>().unwrap()
            .new_canvas(drawable.bounding_box().width(), drawable.bounding_box().height());

        drawable.draw(&canvas, &Point::new(0., 0.));

        canvas.as_any().downcast_ref::<Canvas>().unwrap().snapshot(Path::new("target")
            .join(format!("{}.png", name)).as_ref()).expect("Cannot snap");
    }
}

impl Default for Snapshot {
    fn default() -> Snapshot {
        let root = env!("CARGO_MANIFEST_DIR");
        Snapshot::new(
            &format!("{}/src/test/assets/STIX2Math.otf", root),
            &format!("{}/target", root),
            64.
        )
    }
}<|endoftext|>


<commit_before>
extern crate rand;
// extern crate time;

// use time::PreciseTime;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::{FileStreamReader, FileStreamWriter};
use std::io::Error;
use tftp_specific::{ErrorCode, PacketType};
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;
use std::str;
use std::path::Path;

pub struct EndPoint {
    local_connection: SocketAddrV4,
    // A server doesn't need a remote_connection
    remote_connection: Option<SocketAddrV4>,
}

impl EndPoint {
    pub fn new(remote: &str, port: &str, is_server: bool) -> Result<EndPoint, AddrParseError> {

        let ipv4 = try!(get_ip_from(remote));
        if is_server {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6900),
                remote_connection: None,
            })
        } else {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 9990),
                remote_connection: Some(SocketAddrV4::new(ipv4, 6900)),
            })
        }
    }

    pub fn start_listen(&mut self) -> Result<(), Error> {
        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Start servicing requests from a client
        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        let mut last_blk_id = 0u16;
        match buf[1] {
            1 => {
                // RRQ
                println!("RRQ received");
                // Get filename to be sent from the packet
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }
                let filename = str::from_utf8(&buf[2..i]);
                println!("file requested: {}", filename.unwrap());
                // Send data via the socket
                let mut fs = FileStreamReader::new(String::from(filename.unwrap())).unwrap();
                let (mut buf, num_bytes_read) = fs.next().unwrap();
                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                try!(socket.send_to(v.as_slice(), src));
                // TODO start timer here
                loop {
                    // Get ACK
                    let (amt, src) = try!(socket.recv_from(&mut buf));
                    if buf[1] == 4 {
                        println!("ACK received");
                        last_blk_id += 1;
                        let (buf, num_bytes_read) = fs.next().unwrap();
                        let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                        try!(socket.send_to(v.as_slice(), src));
                    }
                }
            },
            2 => {
                //WRQ
                println!("WRQ received");
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }

                //TODO fix the vec use to copy slice from buf
                let mut v = vec![];
                v.copy_from_slice(&buf[2..i]);
                let filename = str::from_utf8(v.as_slice());
                println!("file requested: {}", filename.unwrap());
                let mut writer = FileStreamWriter::new(String::from(filename.unwrap())).unwrap();
                //send ACK
                let mut block_num = 0u16;
                loop{
                    let low = block_num & 0x00FF;
                    let high = (block_num & 0xFF00) >> 8;

                    println!("Sending ACK");
                    socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    Self::clear_buf(&mut buf);
                    let (amt, src) = try!(socket.recv_from(&mut buf));

                    writer.append(&mut buf);
                    if amt - 4 < 512{
                        //TODO do we close writer here?
                        break;
                    }
                    block_num += 1;

                }

            },
            4 => {}
            _ => panic!("unrecognized packet type"),
        }

        Ok(())

    }

    fn create_error_packet(&mut self, error_code: ErrorCode, err_msg : &str)->Vec<u8>{
        let mut v = Vec::with_capacity(2+2+err_msg.len()+1);
        v.push(0);
        v.push(PacketType::ERROR as u8);
        v.push(0);
        v.push(error_code as u8);
        v.extend_from_slice(err_msg.as_bytes());
        v.push('\0' as u8);
        v
    }

    fn clear_buf(buf : &mut[u8]){
        assert!(buf.len() == 516);
        for i in 0..516{
            buf[i] = 0;
        }
    }

    fn create_data_packet(&mut self, blk_id: u16, buf: &[u8], num_bytes: usize) -> Vec<u8> {
        let mut v = Vec::with_capacity(num_bytes + 4);
        v.push(0);
        v.push(PacketType::DATA as u8);
        v.push((blk_id >> 8) as u8);
        v.push((blk_id & 0x00FF) as u8);
        v.extend_from_slice(&buf[0..num_bytes]);
        v
    }

    fn create_rrq_wrq_packet(&self,
                             p_type: PacketType,
                             file_name: &str,
                             mode: &'static str)
                             -> Vec<u8> {
        let mut v = Vec::with_capacity(2 + file_name.len() + 1 + mode.len() + 1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push('\0' as u8);
        v.extend(mode.as_bytes());
        v.push('\0');//zero terminator
        v
    }

    pub fn get(&mut self, files: &[&str], mode: &'static str) -> Result<(), Error> {
        let socket = try!(UdpSocket::bind(self.local_connection));
        let mut buf = [0; 516];
        for file in files {
            // start with a RRQ
            println!("sending RRQ request");
            let packet = self.create_rrq_wrq_packet(PacketType::RRQ, file, mode);
            try!(socket.send_to(packet.as_slice(), self.remote_connection.unwrap()));
            // TODO remove the hardcoded filename
            let path = Path::new(file);

            println!("Downloading as ./{}", path.file_name().unwrap().to_str().unwrap());
            //TODO fix downloading very file in the current dir
            let mut writer =
                FileStreamWriter::new(format!("./{}", path.file_name().unwrap().to_str().unwrap()))
                    .unwrap();

            loop {
                // get the first block of the requested file
                let (amt, src) = try!(socket.recv_from(&mut buf));
                println!("Received block");
                println!("Total bytes read {}", amt);

                match buf[1] {
                    3 => {
                        let block_size = amt - 4;
                        println!("File block size is {:?}", block_size);
                        if block_size == 0 {
                            println!("Empty block recvd");
                            writer.close();
                            break;
                        }
                        println!("Appending to file");
                        writer.append(&buf[4..4 + block_size]);
                        let block_num: u16 = 0u16 | (buf[2] as u16) << 8 | buf[3] as u16;

                        // send ACK
                        let low = block_num & 0x00FF;
                        let high = (block_num & 0xFF00) >> 8;

                        println!("Sending ACK");
                        socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    }
                    _ => {}
                }
                // Flush buf for next read
                // TODO fix this:
                for i in 0..516 {
                    buf[0] = 0;
                }
            }

        }

        Ok(())
    }
}

fn get_ip_from(ip: &str) -> Result<Ipv4Addr, AddrParseError> {
    Ipv4Addr::from_str(ip)
}
<commit_msg>Add timeout in progress<commit_after>
extern crate rand;
// extern crate time;

// use time::PreciseTime;
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
use file_stream_iter::{FileStreamReader, FileStreamWriter};
use std::io::{ErrorKind, Error};
use tftp_specific::{ErrorCode, PacketType};
use std::str::FromStr;
use std::net::AddrParseError;
use std::error;
use std::str;
use std::path::Path;
use std::time::Duration;

pub struct EndPoint {
    local_connection: SocketAddrV4,
    // A server doesn't need a remote_connection
    remote_connection: Option<SocketAddrV4>,
}

impl EndPoint {
    pub fn new(remote: &str, port: &str, is_server: bool) -> Result<EndPoint, AddrParseError> {

        let ipv4 = try!(get_ip_from(remote));
        if is_server {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 6900),
                remote_connection: None,
            })
        } else {
            Ok(EndPoint {
                local_connection: SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 9990),
                remote_connection: Some(SocketAddrV4::new(ipv4, 6900)),
            })
        }
    }

    pub fn start_listen(&mut self) -> Result<(), Error> {
        // Bind the socket
        let socket = try!(UdpSocket::bind(self.local_connection));

        // Start servicing requests from a client
        // Read from the socket
        let mut buf = [0u8; 516]; //UDP packet is 516 bytes
        let (amt, src) = try!(socket.recv_from(&mut buf));
        let mut last_blk_id = 0u16;
        match buf[1] {
            1 => {
                // RRQ
                println!("RRQ received");
                // Get filename to be sent from the packet
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }
                let filename = str::from_utf8(&buf[2..i]);
                println!("file requested: {}", filename.unwrap());
                // Send data via the socket
                let mut fs = FileStreamReader::new(String::from(filename.unwrap())).unwrap();
                let (mut buf, num_bytes_read) = fs.next().unwrap();
                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                let mut time_out = 3; //3 secs
                socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                try!(socket.send_to(v.as_slice(), src));
                // TODO start timer here
                loop {
                    // Get ACK
                    match (socket.recv_from(&mut buf)){
                        Ok((amt, src)) => {
                            if buf[1] == 4 {
                                println!("ACK received");
                                last_blk_id += 1;
                                let (buf, num_bytes_read) = fs.next().unwrap();
                                let v = self.create_data_packet(last_blk_id, &buf, num_bytes_read);
                                try!(socket.send_to(v.as_slice(), src));
                            }
                        },
                        Err(ref e) if e.kind() == ErrorKind::TimedOut => {
                            time_out += 3;
                            socket.set_read_timeout(Some(Duration::new(time_out, 0)));
                        },
                        Err(e) => {

                        }
                    }
                }
            },
            2 => {
                //WRQ
                println!("WRQ received");
                let mut i = 2;
                while buf[i] != '\0' as u8 {
                    i += 1;
                }

                //TODO fix the vec use to copy slice from buf
                let mut v = vec![];
                v.copy_from_slice(&buf[2..i]);
                let filename = str::from_utf8(v.as_slice());
                println!("file requested: {}", filename.unwrap());
                let mut writer = FileStreamWriter::new(String::from(filename.unwrap())).unwrap();
                //send ACK
                let mut block_num = 0u16;
                loop{
                    let low = block_num & 0x00FF;
                    let high = (block_num & 0xFF00) >> 8;

                    println!("Sending ACK");
                    socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    Self::clear_buf(&mut buf);
                    match (socket.recv_from(&mut buf)){
                        Ok((amt, src)) => {
                            writer.append(&mut buf);
                            if amt - 4 < 512{
                                //TODO do we close writer here?
                                break;
                            }
                            block_num += 1;
                        },
                        Err(ref e) if e.kind() == ErrorKind::TimedOut => {
                            //TODO increase timeout
                        },
                        Err(e) => {}  // bail out
                    }
                }

            },
            4 => {}
            _ => panic!("unrecognized packet type"),
        }

        Ok(())

    }

    fn create_error_packet(&mut self, error_code: ErrorCode, err_msg : &str)->Vec<u8>{
        let mut v = Vec::with_capacity(2+2+err_msg.len()+1);
        v.push(0);
        v.push(PacketType::ERROR as u8);
        v.push(0);
        v.push(error_code as u8);
        v.extend_from_slice(err_msg.as_bytes());
        v.push('\0' as u8);
        v
    }

    fn clear_buf(buf : &mut[u8]){
        assert!(buf.len() == 516);
        for i in 0..516{
            buf[i] = 0;
        }
    }

    fn create_data_packet(&mut self, blk_id: u16, buf: &[u8], num_bytes: usize) -> Vec<u8> {
        let mut v = Vec::with_capacity(num_bytes + 4);
        v.push(0);
        v.push(PacketType::DATA as u8);
        v.push((blk_id >> 8) as u8);
        v.push((blk_id & 0x00FF) as u8);
        v.extend_from_slice(&buf[0..num_bytes]);
        v
    }

    fn create_rrq_wrq_packet(&self,
                             p_type: PacketType,
                             file_name: &str,
                             mode: &'static str)
                             -> Vec<u8> {
        let mut v = Vec::with_capacity(2 + file_name.len() + 1 + mode.len() + 1);
        v.push(0);
        v.push(p_type as u8);
        v.extend(file_name.as_bytes());
        v.push('\0' as u8);
        v.extend(mode.as_bytes());
        v.push('\0' as u8);//zero terminator
        v
    }

    pub fn get(&mut self, files: &[&str], mode: &'static str) -> Result<(), Error> {
        let socket = try!(UdpSocket::bind(self.local_connection));
        let mut buf = [0; 516];
        for file in files {
            // start with a RRQ
            println!("sending RRQ request");
            let packet = self.create_rrq_wrq_packet(PacketType::RRQ, file, mode);
            try!(socket.send_to(packet.as_slice(), self.remote_connection.unwrap()));
            // TODO remove the hardcoded filename
            let path = Path::new(file);

            println!("Downloading as ./{}", path.file_name().unwrap().to_str().unwrap());
            //TODO fix downloading very file in the current dir
            let mut writer =
                FileStreamWriter::new(format!("./{}", path.file_name().unwrap().to_str().unwrap()))
                    .unwrap();

            loop {
                // get the first block of the requested file
                let (amt, src) = try!(socket.recv_from(&mut buf));
                println!("Received block");
                println!("Total bytes read {}", amt);

                match buf[1] {
                    3 => {
                        let block_size = amt - 4;
                        println!("File block size is {:?}", block_size);
                        if block_size == 0 {
                            println!("Empty block recvd");
                            writer.close();
                            break;
                        }
                        println!("Appending to file");
                        writer.append(&buf[4..4 + block_size]);
                        let block_num: u16 = 0u16 | (buf[2] as u16) << 8 | buf[3] as u16;

                        // send ACK
                        let low = block_num & 0x00FF;
                        let high = (block_num & 0xFF00) >> 8;

                        println!("Sending ACK");
                        socket.send_to(&[0, PacketType::ACK as u8, high as u8, low as u8], src);

                    }
                    _ => {}
                }
                // Flush buf for next read
                // TODO fix this:
                for i in 0..516 {
                    buf[0] = 0;
                }
            }

        }

        Ok(())
    }
}

fn get_ip_from(ip: &str) -> Result<Ipv4Addr, AddrParseError> {
    Ipv4Addr::from_str(ip)
}
<|endoftext|>


<commit_before>//! Module to make Rust subclasses of C++ classes. See [`CppSubclass`]
//! for details.

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
    cell::RefCell,
    pin::Pin,
    rc::{Rc, Weak},
};

use cxx::{memory::UniquePtrTarget, UniquePtr};

pub use autocxx_macro::is_subclass;
pub use autocxx_macro::CppSubclassDefault;
pub use autocxx_macro::CppSubclassSelfOwnedDefault;

/// A prelude containing all the traits and macros required to create
/// Rust subclasses of C++ classes. It's recommended that you:
///
/// ```rust
/// use autocxx::subclass::prelude::*;
/// ```
pub mod prelude {
    pub use super::{
        is_subclass, CppPeerConstructor, CppSubclass, CppSubclassDefault, CppSubclassSelfOwned,
        CppSubclassSelfOwnedDefault,
    };
}

#[doc(hidden)]
pub trait CppSubclassCppPeer: UniquePtrTarget {
    fn relinquish_ownership(&self);
}

#[doc(hidden)]
pub enum CppSubclassRustPeerHolder<T> {
    Owned(Rc<RefCell<T>>),
    Unowned(Weak<RefCell<T>>),
}

impl<T> CppSubclassRustPeerHolder<T> {
    pub fn get(&self) -> Option<Rc<RefCell<T>>> {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => Some(strong.clone()),
            CppSubclassRustPeerHolder::Unowned(weak) => weak.upgrade(),
        }
    }
    pub fn relinquish_ownership(self) -> Self {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => {
                CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&strong))
            }
            _ => self,
        }
    }
}

#[doc(hidden)]
pub enum CppSubclassCppPeerHolder<CppPeer: CppSubclassCppPeer> {
    Empty,
    Owned(Box<UniquePtr<CppPeer>>),
    Unowned(*mut CppPeer),
}

impl<CppPeer: CppSubclassCppPeer> Default for CppSubclassCppPeerHolder<CppPeer> {
    fn default() -> Self {
        CppSubclassCppPeerHolder::Empty
    }
}

impl<CppPeer: CppSubclassCppPeer> CppSubclassCppPeerHolder<CppPeer> {
    fn pin_mut(&mut self) -> Pin<&mut CppPeer> {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.pin_mut(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe {
                Pin::new_unchecked(peer.as_mut().unwrap())
            },
        }
    }
    fn get(&self) -> &CppPeer {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.as_ref(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe { peer.as_ref().unwrap() },
        }
    }
    fn set_owned(&mut self, peer: UniquePtr<CppPeer>) {
        *self = Self::Owned(Box::new(peer));
    }
    fn set_unowned(&mut self, peer: &mut UniquePtr<CppPeer>) {
        *self = Self::Unowned(unsafe {
            std::pin::Pin::<&mut CppPeer>::into_inner_unchecked(peer.pin_mut())
        });
    }
}

fn make_owning_peer<CppPeer, PeerConstructor, Subclass, PeerBoxer>(
    me: Subclass,
    peer_constructor: PeerConstructor,
    peer_boxer: PeerBoxer,
) -> Rc<RefCell<Subclass>>
where
    CppPeer: CppSubclassCppPeer,
    Subclass: CppSubclass<CppPeer>,
    PeerConstructor:
        FnOnce(&mut Subclass, CppSubclassRustPeerHolder<Subclass>) -> UniquePtr<CppPeer>,
    PeerBoxer: FnOnce(Rc<RefCell<Subclass>>) -> CppSubclassRustPeerHolder<Subclass>,
{
    let me = Rc::new(RefCell::new(me));
    let holder = peer_boxer(me.clone());
    let cpp_side = peer_constructor(&mut me.as_ref().borrow_mut(), holder);
    me.as_ref()
        .borrow_mut()
        .peer_holder_mut()
        .set_owned(cpp_side);
    me
}

/// A trait to be implemented by a subclass which knows how to construct
/// its C++ peer object. Specifically, the implementation here will
/// arrange to call one or other of the `make_unique` methods to be
/// found on the superclass of the C++ object. If the superclass
/// has a single trivial constructor, then this is implemented
/// automatically for you. If there are multiple constructors, or
/// a single constructor which takes parameters, you'll need to implement
/// this trait for your subclass in order to call the correct
/// constructor.
pub trait CppPeerConstructor<CppPeer: CppSubclassCppPeer>: Sized {
    /// Create the C++ peer. This method will be automatically generated
    /// for you *except* in cases where the superclass has multiple constructors,
    /// or its only constructor takes parameters. In such a case you'll need
    /// to implement this by calling a `make_unique` method on the
    /// `<my subclass name>Cpp` type, passing `peer_holder` as the first
    /// argument.
    fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> UniquePtr<CppPeer>;
}

/// A subclass of a C++ type.
///
/// To create a Rust subclass of a C++ class, you must do these things:
/// * Use the `subclass` directive in your [`crate::include_cpp`] macro (or use
///   the auto-allow mode in your `build.rs`)
/// * Create a `struct` to act as your subclass, and add the #[`is_subclass`] attribute.
///   This adds a field to your struct for autocxx record-keeping.
/// * Use the [`CppSubclass`] trait, and instantiate the subclass using
///   [`CppSubclass::new_rust_owned`] or [`CppSubclass::new_cpp_owned`]
///   constructors. (You can use [`CppSubclassSelfOwned`] if you need that
///   instead; also, see [`CppSubclassDefaultSelfOwned`] and [`CppSubclassDefault`]
///   to arrange for easier constructors to exist.
/// * You _may_ need to implement [`CppPeerConstructor`] for your subclass,
///   but only if autocxx determines that there are multiple possible superclass
///   constructors so you need to call one explicitly (or if there's a single
///   non-trivial superclass constructor.) autocxx will implemente this trait
///   for you if there's no ambiguity.
///
/// # How to access your Rust structure from outside
///
/// Use [`CppSubclass::new_rust_owned`] then use [`std::cell::RefCell::borrow`]
/// or [`std::cell::RefCell::borrow_mut`] to obtain the underlying Rust struct.
///
/// # How to call C++ methods on the subclass
///
/// Do the same. You should find that your subclass struct `impl`s all the
/// C++ methods belonging to the superclass.
///
/// # How to implement virtual methods
///
/// Simply add an `impl` for the `struct`, implementing the relevant method.
/// The C++ virtual function call will be redirected to your Rust implementation.
///
/// # How _not_ to implement virtual methods
///
/// If you don't want to implement a virtual method, don't: the superclass
/// method will be called instead. Naturally, you must implement any pure virtual
/// methods.
///
/// # How it works
///
/// This actually consists of two objects: this object itself and a C++-side
/// peer. The ownership relationship between those two things can work in three
/// different ways:
/// 1. Neither object is owned by Rust. The C++ peer is owned by a C++
///    [`UniquePtr`] held elsewhere in C++. That C++ peer then owns
///    this Rust-side object via a strong [`Rc`] reference. This is the
///    ownership relationship set up by [`CppSubclass::new_cpp_owned`].
/// 2. The object pair is owned by Rust. Specifically, by a strong
///    [`Rc`] reference to this Rust-side object. In turn, the Rust-side object
///    owns the C++-side peer via a [`UniquePtr`]. This is what's set up by
///    [`CppSubclass::new_rust_owned`]. The C++-side peer _does not_ own the Rust
///    object; it just has a weak pointer. (Otherwise we'd get a reference
///    loop and nothing would ever be freed.)
/// 3. The object pair is self-owned and will stay around forever until
///    [`CppSubclassSelfOwned::delete_self`] is called. In this case there's a strong reference
///    from the C++ to the Rust and from the Rust to the C++. This is useful
///    for cases where the subclass is listening for events, and needs to
///    stick around until a particular event occurs then delete itself.
///
/// # Limitations
///
/// The main thing to look out for is re-entrancy. If a (non-const) virtual
/// method is called on your type, which then causes you to call back into C++,
/// which results in a _second_ call into a (non-const) virtual method, we will
/// try to create two mutable references to your subclass which isn't allowed
/// in Rust and will therefore panic.
///
/// A future version of autocxx may provide the option of treating all
/// non-const methods (in C++) as const methods on the Rust side, which will
/// give the option of using interior mutability ([`std::cell::RefCell`])
/// for you to safely handle this situation, whilst remaining compatible
/// with existing C++ interfaces. If you need this, indicate support on
/// [this issue](https://github.com/google/autocxx/issues/622).
pub trait CppSubclass<CppPeer: CppSubclassCppPeer>: CppPeerConstructor<CppPeer> {
    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>;

    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>;

    /// Return a reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer(&self) -> &CppPeer {
        self.peer_holder().get()
    }

    /// Return a mutable reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer_mut(&mut self) -> Pin<&mut CppPeer> {
        self.peer_holder_mut().pin_mut()
    }

    /// Creates a new instance of this subclass. This instance is owned by the
    /// returned [`cxx::UniquePtr`] and thus would typically be returned immediately
    /// to C++ such that it can be owned on the C++ side.
    fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer> {
        let me = Rc::new(RefCell::new(me));
        let holder = CppSubclassRustPeerHolder::Owned(me.clone());
        let mut borrowed = me.as_ref().borrow_mut();
        let mut cpp_side = borrowed.make_peer(holder);
        borrowed.peer_holder_mut().set_unowned(&mut cpp_side);
        cpp_side
    }

    /// Creates a new instance of this subclass. This instance is not owned
    /// by C++, and therefore will be deleted when it goes out of scope in
    /// Rust.
    fn new_rust_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            |me| CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&me)),
        )
    }
}

/// Trait to be implemented by subclasses which are self-owned, i.e. not owned
/// externally by either Rust or C++ code, and thus need the ability to delete
/// themselves when some virtual function is called.
pub trait CppSubclassSelfOwned<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> {
    /// Creates a new instance of this subclass which owns itself.
    /// This is useful
    /// for observers (etc.) which self-register to listen to events.
    /// If an event occurs which would cause this to want to unregister,
    /// use [`CppSubclassSelfOwned::delete_self`].
    /// The return value may be useful to register this, etc. but can ultimately
    /// be discarded without destroying this object.
    fn new_self_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            CppSubclassRustPeerHolder::Owned,
        )
    }

    /// Relinquishes ownership from the C++ side. If there are no outstanding
    /// references from the Rust side, this will result in the destruction
    /// of this subclass instance.
    fn delete_self(&self) {
        self.peer().relinquish_ownership()
    }
}

/// Provides default constructors for subclasses which implement `Default`.
pub trait CppSubclassDefault<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> + Default {
    /// Create a Rust-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_rust_owned() -> Rc<RefCell<Self>> {
        Self::new_rust_owned(Self::default())
    }

    /// Create a C++-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_cpp_owned() -> UniquePtr<CppPeer> {
        Self::new_cpp_owned(Self::default())
    }
}

/// Provides default constructors for subclasses which implement `Default`
/// and are self-owning.
pub trait CppSubclassSelfOwnedDefault<CppPeer: CppSubclassCppPeer>:
    CppSubclassSelfOwned<CppPeer> + Default
{
    /// Create a self-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_self_owned() -> Rc<RefCell<Self>> {
        Self::new_self_owned(Self::default())
    }
}
<commit_msg>More comments.<commit_after>//! Module to make Rust subclasses of C++ classes. See [`CppSubclass`]
//! for details.

// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{
    cell::RefCell,
    pin::Pin,
    rc::{Rc, Weak},
};

use cxx::{memory::UniquePtrTarget, UniquePtr};

pub use autocxx_macro::is_subclass;
pub use autocxx_macro::CppSubclassDefault;
pub use autocxx_macro::CppSubclassSelfOwnedDefault;

/// A prelude containing all the traits and macros required to create
/// Rust subclasses of C++ classes. It's recommended that you:
///
/// ```rust
/// use autocxx::subclass::prelude::*;
/// ```
pub mod prelude {
    pub use super::{
        is_subclass, CppPeerConstructor, CppSubclass, CppSubclassDefault, CppSubclassSelfOwned,
        CppSubclassSelfOwnedDefault,
    };
}

#[doc(hidden)]
pub trait CppSubclassCppPeer: UniquePtrTarget {
    fn relinquish_ownership(&self);
}

#[doc(hidden)]
pub enum CppSubclassRustPeerHolder<T> {
    Owned(Rc<RefCell<T>>),
    Unowned(Weak<RefCell<T>>),
}

impl<T> CppSubclassRustPeerHolder<T> {
    pub fn get(&self) -> Option<Rc<RefCell<T>>> {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => Some(strong.clone()),
            CppSubclassRustPeerHolder::Unowned(weak) => weak.upgrade(),
        }
    }
    pub fn relinquish_ownership(self) -> Self {
        match self {
            CppSubclassRustPeerHolder::Owned(strong) => {
                CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&strong))
            }
            _ => self,
        }
    }
}

#[doc(hidden)]
pub enum CppSubclassCppPeerHolder<CppPeer: CppSubclassCppPeer> {
    Empty,
    Owned(Box<UniquePtr<CppPeer>>),
    Unowned(*mut CppPeer),
}

impl<CppPeer: CppSubclassCppPeer> Default for CppSubclassCppPeerHolder<CppPeer> {
    fn default() -> Self {
        CppSubclassCppPeerHolder::Empty
    }
}

impl<CppPeer: CppSubclassCppPeer> CppSubclassCppPeerHolder<CppPeer> {
    fn pin_mut(&mut self) -> Pin<&mut CppPeer> {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.pin_mut(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe {
                Pin::new_unchecked(peer.as_mut().unwrap())
            },
        }
    }
    fn get(&self) -> &CppPeer {
        match self {
            CppSubclassCppPeerHolder::Empty => panic!("Peer not set up"),
            CppSubclassCppPeerHolder::Owned(peer) => peer.as_ref(),
            CppSubclassCppPeerHolder::Unowned(peer) => unsafe { peer.as_ref().unwrap() },
        }
    }
    fn set_owned(&mut self, peer: UniquePtr<CppPeer>) {
        *self = Self::Owned(Box::new(peer));
    }
    fn set_unowned(&mut self, peer: &mut UniquePtr<CppPeer>) {
        *self = Self::Unowned(unsafe {
            std::pin::Pin::<&mut CppPeer>::into_inner_unchecked(peer.pin_mut())
        });
    }
}

fn make_owning_peer<CppPeer, PeerConstructor, Subclass, PeerBoxer>(
    me: Subclass,
    peer_constructor: PeerConstructor,
    peer_boxer: PeerBoxer,
) -> Rc<RefCell<Subclass>>
where
    CppPeer: CppSubclassCppPeer,
    Subclass: CppSubclass<CppPeer>,
    PeerConstructor:
        FnOnce(&mut Subclass, CppSubclassRustPeerHolder<Subclass>) -> UniquePtr<CppPeer>,
    PeerBoxer: FnOnce(Rc<RefCell<Subclass>>) -> CppSubclassRustPeerHolder<Subclass>,
{
    let me = Rc::new(RefCell::new(me));
    let holder = peer_boxer(me.clone());
    let cpp_side = peer_constructor(&mut me.as_ref().borrow_mut(), holder);
    me.as_ref()
        .borrow_mut()
        .peer_holder_mut()
        .set_owned(cpp_side);
    me
}

/// A trait to be implemented by a subclass which knows how to construct
/// its C++ peer object. Specifically, the implementation here will
/// arrange to call one or other of the `make_unique` methods to be
/// found on the superclass of the C++ object. If the superclass
/// has a single trivial constructor, then this is implemented
/// automatically for you. If there are multiple constructors, or
/// a single constructor which takes parameters, you'll need to implement
/// this trait for your subclass in order to call the correct
/// constructor.
pub trait CppPeerConstructor<CppPeer: CppSubclassCppPeer>: Sized {
    /// Create the C++ peer. This method will be automatically generated
    /// for you *except* in cases where the superclass has multiple constructors,
    /// or its only constructor takes parameters. In such a case you'll need
    /// to implement this by calling a `make_unique` method on the
    /// `<my subclass name>Cpp` type, passing `peer_holder` as the first
    /// argument.
    fn make_peer(&mut self, peer_holder: CppSubclassRustPeerHolder<Self>) -> UniquePtr<CppPeer>;
}

/// A subclass of a C++ type.
///
/// To create a Rust subclass of a C++ class, you must do these things:
/// * Use the `subclass` directive in your [`crate::include_cpp`] macro (or use
///   the auto-allow mode in your `build.rs`)
/// * Create a `struct` to act as your subclass, and add the #[`is_subclass`] attribute.
///   This adds a field to your struct for autocxx record-keeping. You can
///   instead choose to implement [`CppSubclass`] a different way.
/// * Use the [`CppSubclass`] trait, and instantiate the subclass using
///   [`CppSubclass::new_rust_owned`] or [`CppSubclass::new_cpp_owned`]
///   constructors. (You can use [`CppSubclassSelfOwned`] if you need that
///   instead; also, see [`CppSubclassDefaultSelfOwned`] and [`CppSubclassDefault`]
///   to arrange for easier constructors to exist.
/// * You _may_ need to implement [`CppPeerConstructor`] for your subclass,
///   but only if autocxx determines that there are multiple possible superclass
///   constructors so you need to call one explicitly (or if there's a single
///   non-trivial superclass constructor.) autocxx will implemente this trait
///   for you if there's no ambiguity.
///
/// # How to access your Rust structure from outside
///
/// Use [`CppSubclass::new_rust_owned`] then use [`std::cell::RefCell::borrow`]
/// or [`std::cell::RefCell::borrow_mut`] to obtain the underlying Rust struct.
///
/// # How to call C++ methods on the subclass
///
/// Do the same. You should find that your subclass struct `impl`s all the
/// C++ methods belonging to the superclass.
///
/// # How to implement virtual methods
///
/// Simply add an `impl` for the `struct`, implementing the relevant method.
/// The C++ virtual function call will be redirected to your Rust implementation.
///
/// # How _not_ to implement virtual methods
///
/// If you don't want to implement a virtual method, don't: the superclass
/// method will be called instead. Naturally, you must implement any pure virtual
/// methods.
///
/// # How it works
///
/// This actually consists of two objects: this object itself and a C++-side
/// peer. The ownership relationship between those two things can work in three
/// different ways:
/// 1. Neither object is owned by Rust. The C++ peer is owned by a C++
///    [`UniquePtr`] held elsewhere in C++. That C++ peer then owns
///    this Rust-side object via a strong [`Rc`] reference. This is the
///    ownership relationship set up by [`CppSubclass::new_cpp_owned`].
/// 2. The object pair is owned by Rust. Specifically, by a strong
///    [`Rc`] reference to this Rust-side object. In turn, the Rust-side object
///    owns the C++-side peer via a [`UniquePtr`]. This is what's set up by
///    [`CppSubclass::new_rust_owned`]. The C++-side peer _does not_ own the Rust
///    object; it just has a weak pointer. (Otherwise we'd get a reference
///    loop and nothing would ever be freed.)
/// 3. The object pair is self-owned and will stay around forever until
///    [`CppSubclassSelfOwned::delete_self`] is called. In this case there's a strong reference
///    from the C++ to the Rust and from the Rust to the C++. This is useful
///    for cases where the subclass is listening for events, and needs to
///    stick around until a particular event occurs then delete itself.
///
/// # Limitations
///
/// * *Re-entrancy*. The main thing to look out for is re-entrancy. If a
///   (non-const) virtual method is called on your type, which then causes you
///   to call back into C++, which results in a _second_ call into a (non-const)
///   virtual method, we will try to create two mutable references to your
///   subclass which isn't allowed in Rust and will therefore panic.
///
///   A future version of autocxx may provide the option of treating all
///   non-const methods (in C++) as const methods on the Rust side, which will
///   give the option of using interior mutability ([`std::cell::RefCell`])
///   for you to safely handle this situation, whilst remaining compatible
///   with existing C++ interfaces. If you need this, indicate support on
///   [this issue](https://github.com/google/autocxx/issues/622).
///
/// * *Thread safety*. The subclass object is not thread-safe and shouldn't
///   be passed to different threads in C++. A future version of this code
///   will give the option to use `Arc` and `Mutex` internally rather than
///   `Rc` and `RefCell`, solving this problem.
///
/// * *Complex or multiple constructors*. At present, this code doesn't work
///   if the superclass has anything other than a single, zero-argument,
///   constructor. This is
///   https://github.com/google/autocxx/issues/596 and is just a matter of doing
///   a bit of work to plumb this together. (See [`CppPeerConstructor`] for
///   how this will work when it's done.)
///
/// * *Protected methods.* We don't do anything clever here - they're public.
///
/// * *Non-trivial class hierarchies*. We don't yet consider virtual methods
///   on base classes of base classes. This is a temporary limitation,
///   https://github.com/google/autocxx/issues/610.
pub trait CppSubclass<CppPeer: CppSubclassCppPeer>: CppPeerConstructor<CppPeer> {
    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder(&self) -> &CppSubclassCppPeerHolder<CppPeer>;

    /// Return the field which holds the C++ peer object. This is normally
    /// implemented by the #[`is_subclass`] macro, but you're welcome to
    /// implement it yourself if you prefer.
    fn peer_holder_mut(&mut self) -> &mut CppSubclassCppPeerHolder<CppPeer>;

    /// Return a reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer(&self) -> &CppPeer {
        self.peer_holder().get()
    }

    /// Return a mutable reference to the C++ part of this object pair.
    /// This can be used to register listeners, etc.
    fn peer_mut(&mut self) -> Pin<&mut CppPeer> {
        self.peer_holder_mut().pin_mut()
    }

    /// Creates a new instance of this subclass. This instance is owned by the
    /// returned [`cxx::UniquePtr`] and thus would typically be returned immediately
    /// to C++ such that it can be owned on the C++ side.
    fn new_cpp_owned(me: Self) -> UniquePtr<CppPeer> {
        let me = Rc::new(RefCell::new(me));
        let holder = CppSubclassRustPeerHolder::Owned(me.clone());
        let mut borrowed = me.as_ref().borrow_mut();
        let mut cpp_side = borrowed.make_peer(holder);
        borrowed.peer_holder_mut().set_unowned(&mut cpp_side);
        cpp_side
    }

    /// Creates a new instance of this subclass. This instance is not owned
    /// by C++, and therefore will be deleted when it goes out of scope in
    /// Rust.
    fn new_rust_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            |me| CppSubclassRustPeerHolder::Unowned(Rc::downgrade(&me)),
        )
    }
}

/// Trait to be implemented by subclasses which are self-owned, i.e. not owned
/// externally by either Rust or C++ code, and thus need the ability to delete
/// themselves when some virtual function is called.
pub trait CppSubclassSelfOwned<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> {
    /// Creates a new instance of this subclass which owns itself.
    /// This is useful
    /// for observers (etc.) which self-register to listen to events.
    /// If an event occurs which would cause this to want to unregister,
    /// use [`CppSubclassSelfOwned::delete_self`].
    /// The return value may be useful to register this, etc. but can ultimately
    /// be discarded without destroying this object.
    fn new_self_owned(me: Self) -> Rc<RefCell<Self>> {
        make_owning_peer(
            me,
            |obj, holder| obj.make_peer(holder),
            CppSubclassRustPeerHolder::Owned,
        )
    }

    /// Relinquishes ownership from the C++ side. If there are no outstanding
    /// references from the Rust side, this will result in the destruction
    /// of this subclass instance.
    fn delete_self(&self) {
        self.peer().relinquish_ownership()
    }
}

/// Provides default constructors for subclasses which implement `Default`.
pub trait CppSubclassDefault<CppPeer: CppSubclassCppPeer>: CppSubclass<CppPeer> + Default {
    /// Create a Rust-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_rust_owned() -> Rc<RefCell<Self>> {
        Self::new_rust_owned(Self::default())
    }

    /// Create a C++-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_cpp_owned() -> UniquePtr<CppPeer> {
        Self::new_cpp_owned(Self::default())
    }
}

/// Provides default constructors for subclasses which implement `Default`
/// and are self-owning.
pub trait CppSubclassSelfOwnedDefault<CppPeer: CppSubclassCppPeer>:
    CppSubclassSelfOwned<CppPeer> + Default
{
    /// Create a self-owned instance of this subclass, initializing with default values. See
    /// [`CppSubclass`] for more details of the ownership models available.
    fn default_self_owned() -> Rc<RefCell<Self>> {
        Self::new_self_owned(Self::default())
    }
}
<|endoftext|>


<commit_before><commit_msg>Fix failing example<commit_after><|endoftext|>


<commit_before><commit_msg>Add an `instancing.rs` example. (#1163)<commit_after><|endoftext|>


<commit_before>#[macro_use]
extern crate glium;
extern crate rand;
use glium::glutin;

fn main() {
    use glium::DisplayBuild;

    let display = glutin::HeadlessRendererBuilder::new(1024, 1024)
        .build_glium()
        .unwrap();

    let program = glium::program::ComputeShader::from_source(&display, r#"\

            #version 430
            buffer layout(std140);
            layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

            buffer MyBlock {
                float power;
                float values[256];
            };

            void main() {
                float val = values[gl_GlobalInvocationID.x];
                values[gl_GlobalInvocationID.x] = pow(val, power);
            }

        "#).unwrap();

    struct Data {
        power: f32,
        _padding: [f32; 3],
        values: [f32],
    }

    implement_buffer_content!(Data);
    implement_uniform_block!(Data, power, values);

    const NUM_VALUES: usize = 4096;

    let mut buffer: glium::uniforms::UniformBuffer<Data> =
              glium::uniforms::UniformBuffer::empty_unsized(&display, 4 + 4 * NUM_VALUES).unwrap();

    {
        let mut mapping = buffer.map();
        mapping.power = rand::random();
        for val in mapping.values.iter_mut() {
            *val = rand::random();
        }
    }

    program.execute(uniform! { MyBlock: &*buffer }, 4096, 1, 1);

    {
        let mapping = buffer.map();
        println!("Power is: {:?}", mapping.power);
        for val in mapping.values.iter().take(10) {
            println!("{:?}", *val);
        }
        println!("...");
    }
}
<commit_msg>Adjust compute shader example<commit_after>#[macro_use]
extern crate glium;
extern crate rand;
use glium::glutin;

fn main() {
    use glium::DisplayBuild;

    let display = glutin::HeadlessRendererBuilder::new(1024, 1024)
        .build_glium()
        .unwrap();

    let program = glium::program::ComputeShader::from_source(&display, r#"\

            #version 430
            layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;

            layout(std140) buffer MyBlock {
                float power;
                float values[256];
            };

            void main() {
                float val = values[gl_GlobalInvocationID.x];
                values[gl_GlobalInvocationID.x] = pow(val, power);
            }

        "#).unwrap();

    struct Data {
        power: f32,
        _padding: [f32; 3],
        values: [f32],
    }

    implement_buffer_content!(Data);
    implement_uniform_block!(Data, power, values);

    const NUM_VALUES: usize = 4096;

    let mut buffer: glium::uniforms::UniformBuffer<Data> =
              glium::uniforms::UniformBuffer::empty_unsized(&display, 4 + 4 * NUM_VALUES).unwrap();

    {
        let mut mapping = buffer.map();
        mapping.power = rand::random();
        for val in mapping.values.iter_mut() {
            *val = rand::random();
        }
    }

    program.execute(uniform! { MyBlock: &*buffer }, 4096, 1, 1);

    {
        let mapping = buffer.map();
        println!("Power is: {:?}", mapping.power);
        for val in mapping.values.iter().take(10) {
            println!("{:?}", *val);
        }
        println!("...");
    }
}
<|endoftext|>


<commit_before>use ide_db::defs::{Definition, NameRefClass};
use syntax::{ast, AstNode, SyntaxKind, T};

use crate::{
    assist_context::{AssistContext, Assists},
    AssistId, AssistKind,
};

// Assist: add_turbo_fish
//
// Adds `::<_>` to a call of a generic method or function.
//
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make$0();
// }
// ```
// ->
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make::<${0:_}>();
// }
// ```
pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| {
        let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
        if arg_list.args().count() > 0 {
            return None;
        }
        cov_mark::hit!(add_turbo_fish_after_call);
        cov_mark::hit!(add_type_ascription_after_call);
        arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
    })?;
    let next_token = ident.next_token()?;
    if next_token.kind() == T![::] {
        cov_mark::hit!(add_turbo_fish_one_fish_is_enough);
        return None;
    }
    let name_ref = ast::NameRef::cast(ident.parent())?;
    let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
        NameRefClass::Definition(def) => def,
        NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
    };
    let fun = match def {
        Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
        _ => return None,
    };
    let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
    if generics.is_empty() {
        cov_mark::hit!(add_turbo_fish_non_generic);
        return None;
    }

    if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() {
        if let_stmt.colon_token().is_none() {
            let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();
            acc.add(
                AssistId("add_type_ascription", AssistKind::RefactorRewrite),
                "Add `: _` before assignment operator",
                ident.text_range(),
                |builder| match ctx.config.snippet_cap {
                    Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
                    None => builder.insert(type_pos, ": _"),
                },
            )?
        } else {
            cov_mark::hit!(add_type_ascription_already_typed);
        }
    }

    acc.add(
        AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
        "Add `::<>`",
        ident.text_range(),
        |builder| match ctx.config.snippet_cap {
            Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
            None => builder.insert(ident.text_range().end(), "::<_>"),
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};

    use super::*;

    #[test]
    fn add_turbo_fish_function() {
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_after_call() {
        cov_mark::check!(add_turbo_fish_after_call);
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make()$0;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_method() {
        check_assist(
            add_turbo_fish,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make$0();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_one_fish_is_enough() {
        cov_mark::check!(add_turbo_fish_one_fish_is_enough);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make$0::<()>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_non_generic() {
        cov_mark::check!(add_turbo_fish_non_generic);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make() -> () {}
fn main() {
    make$0();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_function() {
        check_assist_by_label(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }

    #[test]
    fn add_type_ascription_after_call() {
        cov_mark::check!(add_type_ascription_after_call);
        check_assist_by_label(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make()$0;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }

    #[test]
    fn add_type_ascription_method() {
        check_assist_by_label(
            add_turbo_fish,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x = S.make$0();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x: ${0:_} = S.make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }

    #[test]
    fn add_type_ascription_already_typed() {
        cov_mark::check!(add_type_ascription_already_typed);
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: () = make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: () = make::<${0:_}>();
}
"#,
        );
    }
}
<commit_msg>fix: add semicolon after type ascription<commit_after>use ide_db::defs::{Definition, NameRefClass};
use syntax::{ast, AstNode, SyntaxKind, T};

use crate::{
    assist_context::{AssistContext, Assists},
    AssistId, AssistKind,
};

// Assist: add_turbo_fish
//
// Adds `::<_>` to a call of a generic method or function.
//
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make$0();
// }
// ```
// ->
// ```
// fn make<T>() -> T { todo!() }
// fn main() {
//     let x = make::<${0:_}>();
// }
// ```
pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let ident = ctx.find_token_syntax_at_offset(SyntaxKind::IDENT).or_else(|| {
        let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
        if arg_list.args().count() > 0 {
            return None;
        }
        cov_mark::hit!(add_turbo_fish_after_call);
        cov_mark::hit!(add_type_ascription_after_call);
        arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
    })?;
    let next_token = ident.next_token()?;
    if next_token.kind() == T![::] {
        cov_mark::hit!(add_turbo_fish_one_fish_is_enough);
        return None;
    }
    let name_ref = ast::NameRef::cast(ident.parent())?;
    let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
        NameRefClass::Definition(def) => def,
        NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
    };
    let fun = match def {
        Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
        _ => return None,
    };
    let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
    if generics.is_empty() {
        cov_mark::hit!(add_turbo_fish_non_generic);
        return None;
    }

    if let Some(let_stmt) = ctx.find_node_at_offset::<ast::LetStmt>() {
        if let_stmt.colon_token().is_none() {
            let type_pos = let_stmt.pat()?.syntax().last_token()?.text_range().end();
            let semi_pos = let_stmt.syntax().last_token()?.text_range().end();

            acc.add(
                AssistId("add_type_ascription", AssistKind::RefactorRewrite),
                "Add `: _` before assignment operator",
                ident.text_range(),
                |builder| {
                    if let_stmt.semicolon_token().is_none() {
                        builder.insert(semi_pos, ";");
                    }
                    match ctx.config.snippet_cap {
                        Some(cap) => builder.insert_snippet(cap, type_pos, ": ${0:_}"),
                        None => builder.insert(type_pos, ": _"),
                    }
                },
            )?
        } else {
            cov_mark::hit!(add_type_ascription_already_typed);
        }
    }

    acc.add(
        AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
        "Add `::<>`",
        ident.text_range(),
        |builder| match ctx.config.snippet_cap {
            Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
            None => builder.insert(ident.text_range().end(), "::<_>"),
        },
    )
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};

    use super::*;

    #[test]
    fn add_turbo_fish_function() {
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_after_call() {
        cov_mark::check!(add_turbo_fish_after_call);
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make()$0;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_method() {
        check_assist(
            add_turbo_fish,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make$0();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    S.make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_one_fish_is_enough() {
        cov_mark::check!(add_turbo_fish_one_fish_is_enough);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    make$0::<()>();
}
"#,
        );
    }

    #[test]
    fn add_turbo_fish_non_generic() {
        cov_mark::check!(add_turbo_fish_non_generic);
        check_assist_not_applicable(
            add_turbo_fish,
            r#"
fn make() -> () {}
fn main() {
    make$0();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_function() {
        check_assist_by_label(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }

    #[test]
    fn add_type_ascription_after_call() {
        cov_mark::check!(add_type_ascription_after_call);
        check_assist_by_label(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make()$0;
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }

    #[test]
    fn add_type_ascription_method() {
        check_assist_by_label(
            add_turbo_fish,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x = S.make$0();
}
"#,
            r#"
struct S;
impl S {
    fn make<T>(&self) -> T {}
}
fn main() {
    let x: ${0:_} = S.make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }

    #[test]
    fn add_type_ascription_already_typed() {
        cov_mark::check!(add_type_ascription_already_typed);
        check_assist(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: () = make$0();
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: () = make::<${0:_}>();
}
"#,
        );
    }

    #[test]
    fn add_type_ascription_append_semicolon() {
        check_assist_by_label(
            add_turbo_fish,
            r#"
fn make<T>() -> T {}
fn main() {
    let x = make$0()
}
"#,
            r#"
fn make<T>() -> T {}
fn main() {
    let x: ${0:_} = make();
}
"#,
            "Add `: _` before assignment operator",
        );
    }
}
<|endoftext|>


<commit_before>//! [POST /_matrix/client/r0/keys/device_signing/upload](https://13301-24998719-gh.circle-artifacts.com/0/scripts/gen/client_server/unstable.html#post-matrix-client-r0-keys-device-signing-upload)

use ruma_api::ruma_api;

use super::CrossSigningKey;
use crate::r0::uiaa::AuthData;

ruma_api! {
    metadata: {
        description: "Publishes cross signing keys for the user.",
        method: POST,
        name: "upload_signing_keys",
        path: "/_matrix/client/r0/keys/device_signing/upload",
        rate_limited: false,
        requires_authentication: true,
    }

    request: {
        /// Additional authentication information for the user-interactive authentication API.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub auth: Option<AuthData>,

        /// The user's master key.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub master_key: Option<CrossSigningKey>,

        /// The user's self-signing key. Must be signed with the accompanied master, or by the
        /// user's most recently uploaded master key if no master key is included in the request.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub self_signing_key: Option<CrossSigningKey>,

        /// The user's user-signing key. Must be signed with the accompanied master, or by the
        /// user's most recently uploaded master key if no master key is included in the request.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub user_signing_key: Option<CrossSigningKey>,
    }

    response: {}

    error: crate::Error
}
<commit_msg>Fixup for f210f916<commit_after>//! [POST /_matrix/client/r0/keys/device_signing/upload](https://13301-24998719-gh.circle-artifacts.com/0/scripts/gen/client_server/unstable.html#post-matrix-client-r0-keys-device-signing-upload)

use ruma_api::ruma_api;

use super::CrossSigningKey;
use crate::r0::uiaa::{AuthData, IncomingAuthData};

ruma_api! {
    metadata: {
        description: "Publishes cross signing keys for the user.",
        method: POST,
        name: "upload_signing_keys",
        path: "/_matrix/client/r0/keys/device_signing/upload",
        rate_limited: false,
        requires_authentication: true,
    }

    request: {
        /// Additional authentication information for the user-interactive authentication API.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub auth: Option<AuthData<'a>>,

        /// The user's master key.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub master_key: Option<CrossSigningKey>,

        /// The user's self-signing key. Must be signed with the accompanied master, or by the
        /// user's most recently uploaded master key if no master key is included in the request.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub self_signing_key: Option<CrossSigningKey>,

        /// The user's user-signing key. Must be signed with the accompanied master, or by the
        /// user's most recently uploaded master key if no master key is included in the request.
        #[serde(skip_serializing_if = "Option::is_none")]
        pub user_signing_key: Option<CrossSigningKey>,
    }

    response: {}

    error: crate::Error
}
<|endoftext|>


<commit_before>use turtle::{Drawing, Turtle};

fn main() {
    let mut drawing = Drawing::new();
    let mut turtle = drawing.add_turtle();

    turtle.set_speed(5);
    turtle.set_pen_size(3.0);
    turtle.set_pen_color("red");

    turtle.pen_up();
    turtle.forward(-50.0);
    turtle.pen_down();

    turtle.set_fill_color("red");
    turtle.begin_fill();
    turtle.left(50.0);
    turtle.forward(111.65);
    turtle.set_speed(7);
    curve(&mut turtle);
    turtle.left(120.0);
    curve(&mut turtle);
    turtle.set_speed(5);
    turtle.forward(111.65);
    turtle.end_fill();

    end_loop(&mut turtle);

    drawing.set_background_color("pink");
}

fn curve(turtle: &mut Turtle) {
    for _ in 0..100 {
        turtle.right(2.0);
        turtle.forward(2.0);
    }
}

fn end_loop(turtle: &mut Turtle) {
    turtle.forward(20.0);
    for _ in 0..10 {
        turtle.right(2.0);
        turtle.forward(3.0);
    }

    let speed = turtle.speed();
    turtle.set_speed(8);
    for _ in 0..60 {
        turtle.forward(1.5);
        turtle.backward(0.5);
        turtle.right(5.0);
    }
    turtle.set_speed(speed);

    turtle.right(15.0);
    turtle.forward(20.0);
    for _ in 0..10 {
        turtle.right(7.0);
        turtle.forward(5.0);
    }
}
<commit_msg>Updating heart example to use the right pen size and no longer require the "backwards hack"<commit_after>use turtle::{Drawing, Turtle};

fn main() {
    let mut drawing = Drawing::new();
    let mut turtle = drawing.add_turtle();

    turtle.set_speed(5);
    turtle.set_pen_size(6.0);
    turtle.set_pen_color("red");

    turtle.pen_up();
    turtle.forward(-50.0);
    turtle.pen_down();

    turtle.set_fill_color("red");
    turtle.begin_fill();
    turtle.left(50.0);
    turtle.forward(111.65);
    turtle.set_speed(7);
    curve(&mut turtle);
    turtle.left(120.0);
    curve(&mut turtle);
    turtle.set_speed(5);
    turtle.forward(111.65);
    turtle.end_fill();

    end_loop(&mut turtle);

    drawing.set_background_color("pink");
}

fn curve(turtle: &mut Turtle) {
    for _ in 0..100 {
        turtle.right(2.0);
        turtle.forward(2.0);
    }
}

fn end_loop(turtle: &mut Turtle) {
    turtle.forward(20.0);
    for _ in 0..10 {
        turtle.right(2.0);
        turtle.forward(3.0);
    }

    let speed = turtle.speed();
    turtle.set_speed(8);
    for _ in 0..60 {
        turtle.forward(1.0);
        turtle.right(5.0);
    }
    turtle.set_speed(speed);

    turtle.right(15.0);
    turtle.forward(20.0);
    for _ in 0..10 {
        turtle.right(7.0);
        turtle.forward(5.0);
    }
}
<|endoftext|>