<commit_before>use wlroots_sys::{wlr_input_device, wlr_pointer};
/// A wlr_input_device that is guaranteed to be a pointer.
pub struct PointerHandle {
    /// The device that refers to this pointer
    device: *mut wlr_input_device,
    /// The underlying pointer data
    pointer: *mut wlr_pointer
}

impl PointerHandle {
    /// Tries to convert an input device to a pointer
    ///
    /// Returns none if it is of a different input varient.
    pub unsafe fn from_input_device(device: *mut wlr_input_device) -> Option<Self> {
        use wlroots_sys::wlr_input_device_type::*;
        match (*device).type_ {
            WLR_INPUT_DEVICE_POINTER => {
                let pointer = (*device).__bindgen_anon_1.pointer;
                Some(PointerHandle { device, pointer })
            }
            _ => None,
        }
    }

    /// Gets the wlr_input_device associated with this Pointer
    pub unsafe fn input_device(&self) -> *mut wlr_input_device {
        self.device
    }
}
<commit_msg>Unsafely expose pointer as well<commit_after>use wlroots_sys::{wlr_input_device, wlr_pointer};

/// A wlr_input_device that is guaranteed to be a pointer.
pub struct PointerHandle {
    /// The device that refers to this pointer
    device: *mut wlr_input_device,
    /// The underlying pointer data
    pointer: *mut wlr_pointer
}

impl PointerHandle {
    /// Tries to convert an input device to a pointer
    ///
    /// Returns none if it is of a different input varient.
    pub unsafe fn from_input_device(device: *mut wlr_input_device) -> Option<Self> {
        use wlroots_sys::wlr_input_device_type::*;
        match (*device).type_ {
            WLR_INPUT_DEVICE_POINTER => {
                let pointer = (*device).__bindgen_anon_1.pointer;
                Some(PointerHandle { device, pointer })
            }
            _ => None,
        }
    }

    /// Gets the wlr_input_device associated with this Pointer
    pub unsafe fn input_device(&self) -> *mut wlr_input_device {
        self.device
    }

    pub unsafe fn pointer(&self) -> *mut wlr_pointer {
        self.pointer
    }
}
<|endoftext|>


<commit_before>extern crate fitsio;
extern crate tempdir;

/* This example docuents the following things:
 *
 * creating a new file
 * writing header keys
 * writing an image into the primary hdu
 * creating a table
 * adding data to a table
 * closing the file
 * re-opening it
 * reading an image region
 * reading some rows from a table column
 */

use std::error::Error;
use tempdir::TempDir;
use fitsio::FitsFile;
use fitsio::fitsfile::ImageDescription;
use fitsio::types::ImageType;
use fitsio::columndescription::{ColumnDataType, ColumnDescription};

fn run() -> Result<(), Box<Error>> {
    /* Create a temporary directory to work from */
    let tmp_dir = TempDir::new("fitsio")?;
    let file_path = tmp_dir.path().join("example.fits");

    // creating a new file with 512 rows and 1024 columns
    let primary_hdu_description = ImageDescription {
        data_type: ImageType::Double,
        dimensions: &[512, 1024],
    };

    {
        let mut fitsfile = FitsFile::create(&file_path)
            .with_custom_primary(&primary_hdu_description)
            .open()?;

        /* We will now add some dummy header keys. We add:
         * - the name of the project (String)
         * - the exposure time (f32)
         * - the image id (i64)
         */

        /* First we get the primary HDU */
        let hdu = fitsfile.primary_hdu()?;

        /* Now we add the header keys */
        hdu.write_key(&mut fitsfile, "PROJECT", "My First Astronomy Project")?;

        /* Now the exposure time */
        hdu.write_key(&mut fitsfile, "EXPTIME", 15.2f32)?;

        /* And finally the image id */
        hdu.write_key(&mut fitsfile, "IMAGE_ID", 20180101010005i64)?;

        /* Now we write some dummy data to the primary HDU. We write the full image in this case.
         * */

        let dummy_data: Vec<f32> = (0..(1024 * 512))
            .map(|val| (val as f32) * 12.5 + 102.5)
            .collect();

        hdu.write_image(&mut fitsfile, &dummy_data)?;

        /* We can create a new image with the following */
        let image_description = ImageDescription {
            data_type: ImageType::Long,
            dimensions: &[256, 256],
        };
        fitsfile.create_image("IMG", &image_description)?;

        /* Now we add a new table HDU called "DATA"
         *
         * We add three columns:
         *
         * 1. Object id (i32)
         * 2. Object name (String, up to 10 characters)
         * 3. Object magnitude (f32)
         * */
        let col1 = ColumnDescription::new("OBJ_ID")
            .with_type(ColumnDataType::Int)
            .create()?;
        let col2 = ColumnDescription::new("NAME")
            .with_type(ColumnDataType::String)
            .that_repeats(10)
            .create()?;
        let col3 = ColumnDescription::new("MAG")
            .with_type(ColumnDataType::Float)
            .create()?;
        let columns = &[col1, col2, col3];
        let table_hdu = fitsfile.create_table("DATA", columns)?;

        /* Add some data to the columns */
        let n_rows = 10;
        let obj_id_data: Vec<i32> = (0..n_rows).collect();
        let name_data: Vec<String> = (0..n_rows).map(|idx| format!("N{}", idx)).collect();
        let mag_data: Vec<f32> = (0..n_rows).map(|idx| -0.2 * idx as f32).collect();

        table_hdu.write_col(&mut fitsfile, "OBJ_ID", &obj_id_data)?;
        table_hdu.write_col(&mut fitsfile, "NAME", &name_data)?;
        table_hdu.write_col(&mut fitsfile, "MAG", &mag_data)?;

        /* `fitsfile` is dropped here at the end of the scope, which closes fhe file on disk */
    }

    /* Here we re-open the file. We want to adjust things, so we use the `edit` method */
    let mut fitsfile = FitsFile::edit(&file_path)?;

    /* Print the fits file contents to stdout */
    fitsfile.pretty_print().expect("printing fits file");

    /* Get the primary HDU and read a section of the image data */
    let phdu = fitsfile.primary_hdu()?;

    /* Let's say we have a region around a star that we want to extract. The star is at (25, 25,
     * 1-indexed) and we want to extract a 5x5 box around it. This means we want to read rows 19 to
     * 19, and columns 19 to 29 (0-indexed). The range arguments are exclusive of the upper bound,
     * so we must use 19..29 for each axis.
     *
     * Note: this is not performant, and if this is the desired use of `fitsio`, I would not
     * suggest this approach. */
    let image_data: Vec<f32> = phdu.read_region(&mut fitsfile, &[&(19..29), &(19..29)])?;
    assert_eq!(image_data.len(), 100);

    /* We can now get the column data. Let's assume we want all of the magnitudes for objects near
     * this one (by index). This object is at index 4 (0-indexed) and we want to read one value
     * before and after it. */
    let table_hdu = fitsfile.hdu("DATA")?;
    let magnitudes: Vec<f32> = table_hdu.read_col_range(&mut fitsfile, "MAG", &(3..6))?;
    assert_eq!(magnitudes.len(), 3);

    /* The file is closed when it is dropped here */

    Ok(())
}

fn main() {
    run().unwrap();
}
<commit_msg>Update full example with row reading<commit_after>extern crate fitsio;
extern crate tempdir;

/* This example docuents the following things:
 *
 * creating a new file
 * writing header keys
 * writing an image into the primary hdu
 * creating a table
 * adding data to a table
 * closing the file
 * re-opening it
 * reading an image region
 * reading some rows from a table column
 */

use std::error::Error;
use tempdir::TempDir;
use fitsio::FitsFile;
use fitsio::fitsfile::ImageDescription;
use fitsio::types::ImageType;
use fitsio::columndescription::{ColumnDataType, ColumnDescription};

fn run() -> Result<(), Box<Error>> {
    /* Create a temporary directory to work from */
    let tmp_dir = TempDir::new("fitsio")?;
    let file_path = tmp_dir.path().join("example.fits");

    // creating a new file with 512 rows and 1024 columns
    let primary_hdu_description = ImageDescription {
        data_type: ImageType::Double,
        dimensions: &[512, 1024],
    };

    {
        let mut fitsfile = FitsFile::create(&file_path)
            .with_custom_primary(&primary_hdu_description)
            .open()?;

        /* We will now add some dummy header keys. We add:
         * - the name of the project (String)
         * - the exposure time (f32)
         * - the image id (i64)
         */

        /* First we get the primary HDU */
        let hdu = fitsfile.primary_hdu()?;

        /* Now we add the header keys */
        hdu.write_key(&mut fitsfile, "PROJECT", "My First Astronomy Project")?;

        /* Now the exposure time */
        hdu.write_key(&mut fitsfile, "EXPTIME", 15.2f32)?;

        /* And finally the image id */
        hdu.write_key(&mut fitsfile, "IMAGE_ID", 20180101010005i64)?;

        /* Now we write some dummy data to the primary HDU. We write the full image in this case.
         * */

        let dummy_data: Vec<f32> = (0..(1024 * 512))
            .map(|val| (val as f32) * 12.5 + 102.5)
            .collect();

        hdu.write_image(&mut fitsfile, &dummy_data)?;

        /* We can create a new image with the following */
        let image_description = ImageDescription {
            data_type: ImageType::Long,
            dimensions: &[256, 256],
        };
        fitsfile.create_image("IMG", &image_description)?;

        /* Now we add a new table HDU called "DATA"
         *
         * We add three columns:
         *
         * 1. Object id (i32)
         * 2. Object name (String, up to 10 characters)
         * 3. Object magnitude (f32)
         * */
        let col1 = ColumnDescription::new("OBJ_ID")
            .with_type(ColumnDataType::Int)
            .create()?;
        let col2 = ColumnDescription::new("NAME")
            .with_type(ColumnDataType::String)
            .that_repeats(10)
            .create()?;
        let col3 = ColumnDescription::new("MAG")
            .with_type(ColumnDataType::Float)
            .create()?;
        let columns = &[col1, col2, col3];
        let table_hdu = fitsfile.create_table("DATA", columns)?;

        /* Add some data to the columns */
        let n_rows = 10;
        let obj_id_data: Vec<i32> = (0..n_rows).collect();
        let name_data: Vec<String> = (0..n_rows).map(|idx| format!("N{}", idx)).collect();
        let mag_data: Vec<f32> = (0..n_rows).map(|idx| -0.2 * idx as f32).collect();

        table_hdu.write_col(&mut fitsfile, "OBJ_ID", &obj_id_data)?;
        table_hdu.write_col(&mut fitsfile, "NAME", &name_data)?;
        table_hdu.write_col(&mut fitsfile, "MAG", &mag_data)?;

        /* `fitsfile` is dropped here at the end of the scope, which closes fhe file on disk */
    }

    /* Here we re-open the file. We want to adjust things, so we use the `edit` method */
    let mut fitsfile = FitsFile::edit(&file_path)?;

    /* Print the fits file contents to stdout */
    fitsfile.pretty_print().expect("printing fits file");

    /* Get the primary HDU and read a section of the image data */
    let phdu = fitsfile.primary_hdu()?;

    /* Let's say we have a region around a star that we want to extract. The star is at (25, 25,
     * 1-indexed) and we want to extract a 5x5 box around it. This means we want to read rows 19 to
     * 19, and columns 19 to 29 (0-indexed). The range arguments are exclusive of the upper bound,
     * so we must use 19..29 for each axis.
     *
     * Note: this is not performant, and if this is the desired use of `fitsio`, I would not
     * suggest this approach. */
    let image_data: Vec<f32> = phdu.read_region(&mut fitsfile, &[&(19..29), &(19..29)])?;
    assert_eq!(image_data.len(), 100);

    /* We can now get the column data. Let's assume we want all of the magnitudes for objects near
     * this one (by index). This object is at index 4 (0-indexed) and we want to read one value
     * before and after it. */
    let table_hdu = fitsfile.hdu("DATA")?;
    let magnitudes: Vec<f32> = table_hdu.read_col_range(&mut fitsfile, "MAG", &(3..6))?;
    assert_eq!(magnitudes.len(), 3);

    /* Read a single row from the file */
    use fitsio::types::TableValue;
    let row = table_hdu.row(&mut fitsfile, 4)?;
    match row["OBJ_ID"] {
        TableValue::Int(val) => assert_eq!(val, 4),
        _ => return Err("invalid column value, should be 4".into()),
    }

    /* The file is closed when it is dropped here */

    Ok(())
}

fn main() {
    run().unwrap();
}
<|endoftext|>


<commit_before>
pub mod text;

pub use self::text::*;

use super::{Element, ColourSource, Source, Pattern, all_pull};
use {OurFont, as_rgba8};
use cgmath::{Vector2, vec2};
use image::{RgbaImage, Rgba};
use rusttype::{FontCollection, Scale, point, PositionedGlyph};
use ui::pattern::Mask;
use std::cmp::max;

pub fn raster(element:&Element, size: Vector2<i32>, fonts: &[OurFont]) -> (RgbaImage, Vector2<i32>) { // secon
    let mut img = RgbaImage::new(size.x as u32, size.y as u32);
    let width = size.x;
    let height = size.y;

    /*
    pub struct Text {
    pub characters : String,
    pub color: Color,
    pub size: i32,
    pub horizontal_alignment: HorizontalAlignment,
    pub vertical_alignment: VerticalAlignment,
}*/

    println!("raster image size {:?} x {:?}", width, height);

    for px in img.pixels_mut() {
        *px = Rgba { data: [0, 0, 0, 0] };
    }

    match element {
        &Element::Draw(ref pattern, ref source) => {
            let s : Box<&ColourSource> = match source {
                &Source::ConstantColour(ref cc) => Box::new(cc),
            };
            match pattern {
                &Pattern::All => all_pull(s, &mut img),
                &Pattern::Border(ref b) => b.pull(s, &mut img),
            }
        },
        &Element::Text(ref text) => {
            let color = as_rgba8(text.color);
            if let Some(font) = fonts.first() {
                let f = &font.font;
                let scale = Scale { x: text.size as f32, y: text.size as f32 };
                let pixel_height = scale.y.ceil() as i32;
                let v_metrics = f.v_metrics(scale);
                let offset = point(0.0, v_metrics.ascent);

                let glyphs: Vec<PositionedGlyph> = f.layout(&text.characters, scale, offset).collect();
                let width = glyphs.iter().rev()
                    .filter_map(|g| g.pixel_bounding_box()
                        .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width))
                    .next().unwrap_or(0.0).ceil() as usize;

                println!("text \"{}\" text raster {:?} x {:?}", text.characters, width, pixel_height);

                for g in glyphs {
//                    println!("glyph pos -> {:?} bb -> {:?}", g.position(), g.pixel_bounding_box());
                    if let Some(bb) = g.pixel_bounding_box() {
                        g.draw(|x, y, v| {
                            let x = x as i32 + bb.min.x;
                            let y = y as i32 + bb.min.y;

                            let tx = x as u32;
                            let ty = (height - 1 - y) as u32;

                            if tx < 0 || tx > width as u32 || ty < 0 || ty > height as u32 {
                                println!("starting x y was {:?} {:?}", x, y);
                                println!("text attempting to write to invalid location ({:?}, {:?}) but space is {:?} x {:?}", tx, ty, width, height);
                            } else {
                                let source = *img.get_pixel(tx, ty);

                                let c_alpha = (255.0 * v) as u8;
                                let new_alpha = max(c_alpha, source.data[3]);

                                let mut c = color;
                                c.data[3] = new_alpha;

                                img.put_pixel(tx, ty, c);
                            }
                        });
                    }
                }
            }
        },
        &Element::Image(ref img) => {
            println!("no image element support yet");
        },
    }

    (img, vec2(0, 0)) // no fancy sizing for now
}
<commit_msg>Removing more debug<commit_after>
pub mod text;

pub use self::text::*;

use super::{Element, ColourSource, Source, Pattern, all_pull};
use {OurFont, as_rgba8};
use cgmath::{Vector2, vec2};
use image::{RgbaImage, Rgba};
use rusttype::{FontCollection, Scale, point, PositionedGlyph};
use ui::pattern::Mask;
use std::cmp::max;

pub fn raster(element:&Element, size: Vector2<i32>, fonts: &[OurFont]) -> (RgbaImage, Vector2<i32>) { // secon
    let mut img = RgbaImage::new(size.x as u32, size.y as u32);
    let width = size.x;
    let height = size.y;

    /*
    pub struct Text {
    pub characters : String,
    pub color: Color,
    pub size: i32,
    pub horizontal_alignment: HorizontalAlignment,
    pub vertical_alignment: VerticalAlignment,
}*/

//    println!("raster image size {:?} x {:?}", width, height);

    for px in img.pixels_mut() {
        *px = Rgba { data: [0, 0, 0, 0] };
    }

    match element {
        &Element::Draw(ref pattern, ref source) => {
            let s : Box<&ColourSource> = match source {
                &Source::ConstantColour(ref cc) => Box::new(cc),
            };
            match pattern {
                &Pattern::All => all_pull(s, &mut img),
                &Pattern::Border(ref b) => b.pull(s, &mut img),
            }
        },
        &Element::Text(ref text) => {
            let color = as_rgba8(text.color);
            if let Some(font) = fonts.first() {
                let f = &font.font;
                let scale = Scale { x: text.size as f32, y: text.size as f32 };
                let pixel_height = scale.y.ceil() as i32;
                let v_metrics = f.v_metrics(scale);
                let offset = point(0.0, v_metrics.ascent);

                let glyphs: Vec<PositionedGlyph> = f.layout(&text.characters, scale, offset).collect();
                let width = glyphs.iter().rev()
                    .filter_map(|g| g.pixel_bounding_box()
                        .map(|b| b.min.x as f32 + g.unpositioned().h_metrics().advance_width))
                    .next().unwrap_or(0.0).ceil() as usize;

//                println!("text \"{}\" text raster {:?} x {:?}", text.characters, width, pixel_height);

                for g in glyphs {
//                    println!("glyph pos -> {:?} bb -> {:?}", g.position(), g.pixel_bounding_box());
                    if let Some(bb) = g.pixel_bounding_box() {
                        g.draw(|x, y, v| {
                            let x = x as i32 + bb.min.x;
                            let y = y as i32 + bb.min.y;

                            let tx = x as u32;
                            let ty = (height - 1 - y) as u32;

                            if tx < 0 || tx > width as u32 || ty < 0 || ty > height as u32 {
                                println!("starting x y was {:?} {:?}", x, y);
                                println!("text attempting to write to invalid location ({:?}, {:?}) but space is {:?} x {:?}", tx, ty, width, height);
                            } else {
                                let source = *img.get_pixel(tx, ty);

                                let c_alpha = (255.0 * v) as u8;
                                let new_alpha = max(c_alpha, source.data[3]);

                                let mut c = color;
                                c.data[3] = new_alpha;

                                img.put_pixel(tx, ty, c);
                            }
                        });
                    }
                }
            }
        },
        &Element::Image(ref img) => {
//            println!("no image element support yet");
        },
    }

    (img, vec2(0, 0)) // no fancy sizing for now
}
<|endoftext|>


<commit_before>#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate lzma_rs;
extern crate xz2;

use std::io::Read;
use lzma_rs::error::Result;
use xz2::stream;

fn decode_xz_lzmars(compressed: &[u8]) -> Result<Vec<u8>> {
    let mut bf = std::io::Cursor::new(compressed);
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::xz_decompress(&mut bf, &mut decomp)?;
    Ok(decomp)
}

fn decode_xz_xz2(compressed: &[u8]) -> Result<Vec<u8>> {
    let bf = std::io::Cursor::new(compressed);
    let mut decomp: Vec<u8> = Vec::new();
    // create new XZ decompression stream with 8Gb memory limit and checksum verification disabled
    let xz_stream = stream::Stream::new_stream_decoder(8589935000, stream::IGNORE_CHECK).expect("Failed to create stream");
    xz2::bufread::XzDecoder::new_stream(bf, xz_stream).read_to_end(&mut decomp)?;
    Ok(decomp)
}

fuzz_target!(|data: &[u8]| {
    let result_lzmars = decode_xz_lzmars(data);
    let result_xz2 = decode_xz_xz2(data);
    match (result_lzmars, result_xz2) {
        (Err(_), Err(_)) => (), // both failed, so behavior matches
        (Ok(_), Err(_)) => panic!("lzma-rs succeeded but xz2 failed"),
        (Err(_), Ok(_)) => panic!("xz2 succeeded but lzma-rs failed"),
        (Ok(a), Ok(b)) => assert!(a == b)
    }
});
<commit_msg>More readable 8Gb<commit_after>#![no_main]
#[macro_use]
extern crate libfuzzer_sys;
extern crate lzma_rs;
extern crate xz2;

use std::io::Read;
use lzma_rs::error::Result;
use xz2::stream;

fn decode_xz_lzmars(compressed: &[u8]) -> Result<Vec<u8>> {
    let mut bf = std::io::Cursor::new(compressed);
    let mut decomp: Vec<u8> = Vec::new();
    lzma_rs::xz_decompress(&mut bf, &mut decomp)?;
    Ok(decomp)
}

fn decode_xz_xz2(compressed: &[u8]) -> Result<Vec<u8>> {
    let bf = std::io::Cursor::new(compressed);
    let mut decomp: Vec<u8> = Vec::new();
    // create new XZ decompression stream with 8Gb memory limit and checksum verification disabled
    let xz_stream = stream::Stream::new_stream_decoder(8*1024*1024*1024, stream::IGNORE_CHECK).expect("Failed to create stream");
    xz2::bufread::XzDecoder::new_stream(bf, xz_stream).read_to_end(&mut decomp)?;
    Ok(decomp)
}

fuzz_target!(|data: &[u8]| {
    let result_lzmars = decode_xz_lzmars(data);
    let result_xz2 = decode_xz_xz2(data);
    match (result_lzmars, result_xz2) {
        (Err(_), Err(_)) => (), // both failed, so behavior matches
        (Ok(_), Err(_)) => panic!("lzma-rs succeeded but xz2 failed"),
        (Err(_), Ok(_)) => panic!("xz2 succeeded but lzma-rs failed"),
        (Ok(a), Ok(b)) => assert!(a == b)
    }
});
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use move_cli::base::prove::run_move_prover;
use std::path::PathBuf;
use tempfile::tempdir;

pub fn path_in_crate<S>(relative: S) -> PathBuf
where
    S: Into<String>,
{
    let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    path.push(relative.into());
    path
}

pub fn run_prover_for_pkg(path_to_pkg: impl Into<String>) {
    let pkg_path = path_in_crate(path_to_pkg);
    let config = move_package::BuildConfig {
        test_mode: true,
        install_dir: Some(tempdir().unwrap().path().to_path_buf()),
        ..Default::default()
    };
    run_move_prover(
        config,
        &pkg_path,
        &None,
        true,
        move_prover::cli::Options::default(),
    )
    .unwrap();
}

#[ignore]
#[test]
fn move_framework_prover_tests() {
    run_prover_for_pkg("aptos-framework");
}

#[ignore]
#[test]
fn move_names_prover_tests() {
    run_prover_for_pkg("aptos-names");
}

#[ignore]
#[test]
fn move_token_prover_tests() {
    run_prover_for_pkg("aptos-token");
}

#[ignore]
#[test]
fn move_aptos_stdlib_prover_tests() {
    run_prover_for_pkg("aptos-stdlib");
}

#[ignore]
#[test]
fn move_stdlib_prover_tests() {
    run_prover_for_pkg("move-stdlib");
}
<commit_msg>Update move_prover_tests.rs (#4814)<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

use move_cli::base::prove::run_move_prover;
use std::path::PathBuf;
use tempfile::tempdir;

pub fn path_in_crate<S>(relative: S) -> PathBuf
where
    S: Into<String>,
{
    let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    path.push(relative.into());
    path
}

pub fn run_prover_for_pkg(path_to_pkg: impl Into<String>) {
    let pkg_path = path_in_crate(path_to_pkg);
    let config = move_package::BuildConfig {
        test_mode: true,
        install_dir: Some(tempdir().unwrap().path().to_path_buf()),
        ..Default::default()
    };
    run_move_prover(
        config,
        &pkg_path,
        &None,
        true,
        move_prover::cli::Options::default(),
    )
    .unwrap();
}

#[ignore]
#[test]
fn move_framework_prover_tests() {
    run_prover_for_pkg("aptos-framework");
}

#[ignore]
#[test]
fn move_names_prover_tests() {
    // run_prover_for_pkg("aptos-names"); // TODO: disabled due to the unsupported syntax used.
}

#[ignore]
#[test]
fn move_token_prover_tests() {
    run_prover_for_pkg("aptos-token");
}

#[ignore]
#[test]
fn move_aptos_stdlib_prover_tests() {
    run_prover_for_pkg("aptos-stdlib");
}

#[ignore]
#[test]
fn move_stdlib_prover_tests() {
    run_prover_for_pkg("move-stdlib");
}
<|endoftext|>


<commit_before>extern crate adventofcode;
use adventofcode::d2::{Parser, Program};
use std::io;
use std::io::BufRead;

fn program_for(inp: &str, noun: i64, verb: i64) -> i64 {
    let v: Vec<i64> = Vec::new();
    let mut p = Program::new(Parser::parse(&inp));
    p[1] = noun;
    p[2] = verb;
    p.run(Box::new(v.into_iter())).unwrap();
    p[0]
}

fn search_for(inp: &str, val: i64) -> Option<(i64, i64)> {
    let v = Parser::parse(inp);
    let len = v.len() as i64;
    // We know that the only valid values are those which can be indices into the array, and
    // therefore they must also be smaller than the array size.
    for i in 0..len {
        for j in 0..len {
            if program_for(inp, i, j) == val {
                return Some((i, j));
            }
        }
    }
    None
}

fn main() -> io::Result<()> {
    let b = io::BufReader::new(io::stdin());
    if let Some(inp) = b.lines().next() {
        let inp = &inp?;
        println!("{}", program_for(inp, 12, 2));
        match search_for(inp, 19690720) {
            Some((noun, verb)) => println!("{}", 100 * noun + verb),
            None => eprintln!("No solution found"),
        }
    }
    Ok(())
}
<commit_msg>d2: use underscores in large numbers<commit_after>extern crate adventofcode;
use adventofcode::d2::{Parser, Program};
use std::io;
use std::io::BufRead;

fn program_for(inp: &str, noun: i64, verb: i64) -> i64 {
    let v: Vec<i64> = Vec::new();
    let mut p = Program::new(Parser::parse(&inp));
    p[1] = noun;
    p[2] = verb;
    p.run(Box::new(v.into_iter())).unwrap();
    p[0]
}

fn search_for(inp: &str, val: i64) -> Option<(i64, i64)> {
    let v = Parser::parse(inp);
    let len = v.len() as i64;
    // We know that the only valid values are those which can be indices into the array, and
    // therefore they must also be smaller than the array size.
    for i in 0..len {
        for j in 0..len {
            if program_for(inp, i, j) == val {
                return Some((i, j));
            }
        }
    }
    None
}

fn main() -> io::Result<()> {
    let b = io::BufReader::new(io::stdin());
    if let Some(inp) = b.lines().next() {
        let inp = &inp?;
        println!("{}", program_for(inp, 12, 2));
        match search_for(inp, 19_690_720) {
            Some((noun, verb)) => println!("{}", 100 * noun + verb),
            None => eprintln!("No solution found"),
        }
    }
    Ok(())
}
<|endoftext|>


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

mod fetcher;
mod storage;

use anyhow::{Error, Result};
use fastly::{
    http::{StatusCode, Url},
    mime::Mime,
    Request, Response,
};
use fetcher::FastlyFetcher;
use std::convert::TryInto;
use sxg_rs::{
    crypto::CertificateChain,
    headers::{AcceptFilter, Headers, VIA_SXGRS},
    http::HeaderFields,
    PresetContent, SxgWorker,
};
use url::Origin;

/// The name of Fastly dictionary to be used as worker's runtime storage.
const DICTIONARY_NAME: &str = "config";

async fn create_worker() -> SxgWorker {
    let dict = fastly::ConfigStore::open(DICTIONARY_NAME);
    let mut worker = ::sxg_rs::SxgWorker::new(&dict.get("sxg-config-input").unwrap()).unwrap();
    let preissued = (dict.get("cert-pem"), dict.get("issuer-pem"));
    if let (Some(cert_pem), Some(issuer_pem)) = preissued {
        let certificate = CertificateChain::from_pem_files(&[&cert_pem, &issuer_pem]).unwrap();
        worker.add_certificate(certificate);
    }
    let runtime = sxg_rs::runtime::Runtime {
        storage: Box::new(storage::FastlyStorage::new("config")),
        ..Default::default()
    };
    worker
        .add_acme_certificates_from_storage(&runtime)
        .await
        .unwrap();
    worker
}

fn binary_response(status_code: StatusCode, content_type: Mime, body: &[u8]) -> Response {
    let mut response = Response::new();
    response.set_status(status_code);
    response.set_content_type(content_type);
    response.set_body(body);
    response
}

fn text_response(body: &str) -> Response {
    binary_response(StatusCode::OK, fastly::mime::TEXT_PLAIN, body.as_bytes())
}

async fn get_req_header_fields(
    worker: &SxgWorker,
    req: &Request,
    accept_filter: AcceptFilter,
) -> Result<HeaderFields> {
    let mut fields: Vec<(String, String)> = vec![];
    for name in req.get_header_names() {
        for value in req.get_header_all(name) {
            let value = value.to_str().map_err(|_| {
                Error::msg(format!(r#"Header "{}" contains non-ASCII value."#, name))
            })?;
            fields.push((name.as_str().to_string(), value.to_string()))
        }
    }
    worker.transform_request_headers(fields, accept_filter)
}

async fn get_rsp_header_fields(worker: &SxgWorker, rsp: &Response) -> Result<Headers> {
    let mut fields: Vec<(String, String)> = vec![];
    for name in rsp.get_header_names() {
        for value in rsp.get_header_all(name) {
            let value = value.to_str().map_err(|_| {
                Error::msg(format!(r#"Header "{}" contains non-ASCII value."#, name))
            })?;
            fields.push((name.as_str().to_string(), value.to_string()))
        }
    }
    worker.transform_payload_headers(fields)
}

pub fn sxg_rs_response_to_fastly_response(
    rsp: sxg_rs::http::HttpResponse,
) -> anyhow::Result<fastly::Response> {
    let rsp: ::http::response::Response<Vec<u8>> = rsp.try_into()?;
    let rsp: ::http::response::Response<fastly::Body> = rsp.map(From::<Vec<u8>>::from);
    Ok(rsp.into())
}

/// The *name* of the host in Fastly service configuration.
/// https://docs.fastly.com/en/guides/working-with-hosts
const HTML_BACKEND_NAME: &str = "Origin HTML server";

fn fetch_from_html_server(url: &Url, req_headers: Vec<(String, String)>) -> Result<Response> {
    let mut req = Request::new("GET", url);
    for (name, value) in req_headers {
        req.append_header(name, value);
    }
    req.send(HTML_BACKEND_NAME)
        .map_err(|err| Error::msg(format!(r#"Fetching "{}" leads to error "{}""#, url, err)))
}

async fn generate_sxg_response(
    worker: &SxgWorker,
    fallback_url: &Url,
    cert_origin: Origin,
    payload: Response,
) -> Result<Response> {
    let payload_headers = get_rsp_header_fields(worker, &payload).await?;
    let payload_body = payload.into_body_bytes();
    let cert_origin = cert_origin.ascii_serialization();
    let runtime = sxg_rs::runtime::Runtime {
        now: std::time::SystemTime::now(),
        fetcher: Box::new(FastlyFetcher::new("subresources")),
        storage: Box::new(storage::FastlyStorage::new("config")),
        sxg_signer: Box::new(worker.create_rust_signer().unwrap()),
        ..Default::default()
    };
    let sxg = worker.create_signed_exchange(
        &runtime,
        sxg_rs::CreateSignedExchangeParams {
            payload_body: &payload_body,
            payload_headers,
            skip_process_link: false,
            status_code: 200,
            fallback_url: fallback_url.as_str(),
            cert_origin: &cert_origin,
            // The fastly crate provides only read access to dictionaries, so
            // header integrities cannot be cached. However, I believe the
            // subresource_fetcher will go through the cache.
            header_integrity_cache: sxg_rs::http_cache::NullCache {},
        },
    );
    let sxg = sxg.await?;
    sxg_rs_response_to_fastly_response(sxg)
}

async fn handle_request(worker: &SxgWorker, req: &Request) -> Result<Response> {
    let runtime = sxg_rs::runtime::Runtime {
        now: std::time::SystemTime::now(),
        fetcher: Box::new(FastlyFetcher::new("OCSP server")),
        storage: Box::new(storage::FastlyStorage::new("config")),
        ..Default::default()
    };
    let fallback_url: Url;
    let cert_origin: Origin;
    let sxg_payload;
    let preset_content = worker
        .serve_preset_content(&runtime, req.get_url_str())
        .await;
    match preset_content {
        Some(PresetContent::Direct(response)) => {
            return sxg_rs_response_to_fastly_response(response)
        }
        Some(PresetContent::ToBeSigned { url, payload, .. }) => {
            fallback_url = Url::parse(&url).map_err(Error::new)?;
            (_, cert_origin) = worker.get_fallback_url_and_cert_origin(req.get_url())?;
            sxg_payload = sxg_rs_response_to_fastly_response(payload)?;
            get_req_header_fields(worker, req, AcceptFilter::AcceptsSxg).await?;
        }
        None => {
            (fallback_url, cert_origin) = worker.get_fallback_url_and_cert_origin(req.get_url())?;
            let req_headers = get_req_header_fields(worker, req, AcceptFilter::PrefersSxg).await?;
            sxg_payload = fetch_from_html_server(&fallback_url, req_headers)?;
        }
    };
    generate_sxg_response(worker, &fallback_url, cert_origin, sxg_payload).await
}

#[fastly::main]
fn main(req: Request) -> Result<Response, std::convert::Infallible> {
    let has_network_loop = req
        .get_header_all_str("via")
        .iter()
        .any(|v| v.contains(VIA_SXGRS));
    if has_network_loop {
        return Ok(text_response("Network loop detected."));
    }
    tokio::runtime::Builder::new_current_thread()
        .build()
        .unwrap()
        .block_on(async {
            let worker = create_worker().await;
            let response = handle_request(&worker, &req).await.unwrap_or_else(|_| {
                let mut req = req;
                match worker.get_fallback_url_and_cert_origin(req.get_url()) {
                    Ok((fallback_url, _)) => {
                        req.set_url(fallback_url);
                    }
                    Err(_) => {
                        return text_response("Failed to construct fallback URL");
                    }
                };
                req.append_header("via", VIA_SXGRS);
                req.send(HTML_BACKEND_NAME).unwrap()
            });
            Ok(response)
        })
}
<commit_msg>Use error type from fastly crate (#400)<commit_after>// 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.

mod fetcher;
mod storage;

use anyhow::{Error, Result};
use fastly::{http::Url, Error as FastlyError, Request, Response};
use fetcher::FastlyFetcher;
use std::convert::TryInto;
use sxg_rs::{
    crypto::CertificateChain,
    headers::{AcceptFilter, Headers, VIA_SXGRS},
    http::HeaderFields,
    PresetContent, SxgWorker,
};
use url::Origin;

/// The name of Fastly dictionary to be used as worker's runtime storage.
const DICTIONARY_NAME: &str = "config";

async fn create_worker() -> SxgWorker {
    let dict = fastly::ConfigStore::open(DICTIONARY_NAME);
    let mut worker = ::sxg_rs::SxgWorker::new(&dict.get("sxg-config-input").unwrap()).unwrap();
    let preissued = (dict.get("cert-pem"), dict.get("issuer-pem"));
    if let (Some(cert_pem), Some(issuer_pem)) = preissued {
        let certificate = CertificateChain::from_pem_files(&[&cert_pem, &issuer_pem]).unwrap();
        worker.add_certificate(certificate);
    }
    let runtime = sxg_rs::runtime::Runtime {
        storage: Box::new(storage::FastlyStorage::new("config")),
        ..Default::default()
    };
    worker
        .add_acme_certificates_from_storage(&runtime)
        .await
        .unwrap();
    worker
}

async fn get_req_header_fields(
    worker: &SxgWorker,
    req: &Request,
    accept_filter: AcceptFilter,
) -> Result<HeaderFields> {
    let mut fields: Vec<(String, String)> = vec![];
    for name in req.get_header_names() {
        for value in req.get_header_all(name) {
            let value = value.to_str().map_err(|_| {
                Error::msg(format!(r#"Header "{}" contains non-ASCII value."#, name))
            })?;
            fields.push((name.as_str().to_string(), value.to_string()))
        }
    }
    worker.transform_request_headers(fields, accept_filter)
}

async fn get_rsp_header_fields(worker: &SxgWorker, rsp: &Response) -> Result<Headers> {
    let mut fields: Vec<(String, String)> = vec![];
    for name in rsp.get_header_names() {
        for value in rsp.get_header_all(name) {
            let value = value.to_str().map_err(|_| {
                Error::msg(format!(r#"Header "{}" contains non-ASCII value."#, name))
            })?;
            fields.push((name.as_str().to_string(), value.to_string()))
        }
    }
    worker.transform_payload_headers(fields)
}

pub fn sxg_rs_response_to_fastly_response(
    rsp: sxg_rs::http::HttpResponse,
) -> anyhow::Result<fastly::Response> {
    let rsp: ::http::response::Response<Vec<u8>> = rsp.try_into()?;
    let rsp: ::http::response::Response<fastly::Body> = rsp.map(From::<Vec<u8>>::from);
    Ok(rsp.into())
}

/// The *name* of the host in Fastly service configuration.
/// https://docs.fastly.com/en/guides/working-with-hosts
const HTML_BACKEND_NAME: &str = "Origin HTML server";

fn fetch_from_html_server(url: &Url, req_headers: Vec<(String, String)>) -> Result<Response> {
    let mut req = Request::new("GET", url);
    for (name, value) in req_headers {
        req.append_header(name, value);
    }
    req.send(HTML_BACKEND_NAME)
        .map_err(|err| Error::msg(format!(r#"Fetching "{}" leads to error "{}""#, url, err)))
}

async fn generate_sxg_response(
    worker: &SxgWorker,
    fallback_url: &Url,
    cert_origin: Origin,
    payload: Response,
) -> Result<Response> {
    let payload_headers = get_rsp_header_fields(worker, &payload).await?;
    let payload_body = payload.into_body_bytes();
    let cert_origin = cert_origin.ascii_serialization();
    let runtime = sxg_rs::runtime::Runtime {
        now: std::time::SystemTime::now(),
        fetcher: Box::new(FastlyFetcher::new("subresources")),
        storage: Box::new(storage::FastlyStorage::new("config")),
        sxg_signer: Box::new(worker.create_rust_signer().unwrap()),
        ..Default::default()
    };
    let sxg = worker.create_signed_exchange(
        &runtime,
        sxg_rs::CreateSignedExchangeParams {
            payload_body: &payload_body,
            payload_headers,
            skip_process_link: false,
            status_code: 200,
            fallback_url: fallback_url.as_str(),
            cert_origin: &cert_origin,
            // The fastly crate provides only read access to dictionaries, so
            // header integrities cannot be cached. However, I believe the
            // subresource_fetcher will go through the cache.
            header_integrity_cache: sxg_rs::http_cache::NullCache {},
        },
    );
    let sxg = sxg.await?;
    sxg_rs_response_to_fastly_response(sxg)
}

async fn handle_request(worker: &SxgWorker, req: &Request) -> Result<Response> {
    let runtime = sxg_rs::runtime::Runtime {
        now: std::time::SystemTime::now(),
        fetcher: Box::new(FastlyFetcher::new("OCSP server")),
        storage: Box::new(storage::FastlyStorage::new("config")),
        ..Default::default()
    };
    let fallback_url: Url;
    let cert_origin: Origin;
    let sxg_payload;
    let preset_content = worker
        .serve_preset_content(&runtime, req.get_url_str())
        .await;
    match preset_content {
        Some(PresetContent::Direct(response)) => {
            return sxg_rs_response_to_fastly_response(response)
        }
        Some(PresetContent::ToBeSigned { url, payload, .. }) => {
            fallback_url = Url::parse(&url).map_err(Error::new)?;
            (_, cert_origin) = worker.get_fallback_url_and_cert_origin(req.get_url())?;
            sxg_payload = sxg_rs_response_to_fastly_response(payload)?;
            get_req_header_fields(worker, req, AcceptFilter::AcceptsSxg).await?;
        }
        None => {
            (fallback_url, cert_origin) = worker.get_fallback_url_and_cert_origin(req.get_url())?;
            let req_headers = get_req_header_fields(worker, req, AcceptFilter::PrefersSxg).await?;
            sxg_payload = fetch_from_html_server(&fallback_url, req_headers)?;
        }
    };
    generate_sxg_response(worker, &fallback_url, cert_origin, sxg_payload).await
}

#[fastly::main]
fn main(req: Request) -> Result<Response, FastlyError> {
    let has_network_loop = req
        .get_header_all_str("via")
        .iter()
        .any(|v| v.contains(VIA_SXGRS));
    if has_network_loop {
        return Err(FastlyError::msg("Network loop detected."));
    }
    tokio::runtime::Builder::new_current_thread()
        .build()
        .unwrap()
        .block_on(async {
            let worker = create_worker().await;
            match handle_request(&worker, &req).await {
                Ok(sxg_response) => Ok(sxg_response),
                Err(_) => {
                    let mut req = req;
                    let (fallback_url, _) = worker
                        .get_fallback_url_and_cert_origin(req.get_url())
                        .map_err(|_| FastlyError::msg("Failed to construct fallback URL"))?;
                    req.set_url(fallback_url);
                    req.append_header("via", VIA_SXGRS);
                    req.send(HTML_BACKEND_NAME)
                        .map_err(|_| FastlyError::msg("Failed to fetch from fallback URL"))
                }
            }
        })
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use windows::processor::{create_processor, CounterValue, Processor, Query};

use sys::disk::{new_disk, Disk, DiskType};

use std::collections::HashMap;
use std::ffi::OsStr;
use std::mem::{size_of, zeroed};

use winapi::ctypes::c_void;

use winapi::shared::minwindef::{BYTE, DWORD, MAX_PATH, TRUE};
use winapi::um::fileapi::{
    CreateFileW, GetDriveTypeW, GetLogicalDrives, GetVolumeInformationW, OPEN_EXISTING,
};
use winapi::um::handleapi::CloseHandle;
use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::sysinfoapi::{
    GetSystemInfo, GetTickCount64, SYSTEM_INFO,
};
use winapi::um::winioctl::{
    DISK_GEOMETRY, IOCTL_STORAGE_QUERY_PROPERTY, IOCTL_DISK_GET_DRIVE_GEOMETRY,
};
use winapi::um::winnt::{
    BOOLEAN, FILE_SHARE_READ, FILE_SHARE_WRITE, HANDLE,
};
use winapi::um::winbase::DRIVE_FIXED;

pub struct KeyHandler {
    pub unique_id: String,
    pub win_key: Vec<u16>,
}

impl KeyHandler {
    pub fn new(unique_id: String, win_key: Vec<u16>) -> KeyHandler {
        KeyHandler {
            unique_id: unique_id,
            win_key: win_key,
        }
    }
}

/*#[allow(non_snake_case)]
#[allow(unused)]
unsafe fn browser() {
    use winapi::um::pdh::{PdhBrowseCountersA, PDH_BROWSE_DLG_CONFIG_A};
    use winapi::shared::winerror::ERROR_SUCCESS;

    let mut BrowseDlgData: PDH_BROWSE_DLG_CONFIG_A = ::std::mem::zeroed();
    let mut CounterPathBuffer: [i8; 255] = ::std::mem::zeroed();
    const PERF_DETAIL_WIZARD: u32 = 400;
    let text = b"Select a counter to monitor.\0";

    BrowseDlgData.set_IncludeInstanceIndex(FALSE as u32);
    BrowseDlgData.set_SingleCounterPerAdd(TRUE as u32);
    BrowseDlgData.set_SingleCounterPerDialog(TRUE as u32);
    BrowseDlgData.set_LocalCountersOnly(FALSE as u32);
    BrowseDlgData.set_WildCardInstances(TRUE as u32);
    BrowseDlgData.set_HideDetailBox(TRUE as u32);
    BrowseDlgData.set_InitializePath(FALSE as u32);
    BrowseDlgData.set_DisableMachineSelection(FALSE as u32);
    BrowseDlgData.set_IncludeCostlyObjects(FALSE as u32);
    BrowseDlgData.set_ShowObjectBrowser(FALSE as u32);
    BrowseDlgData.hWndOwner = ::std::ptr::null_mut();
    BrowseDlgData.szReturnPathBuffer = CounterPathBuffer.as_mut_ptr();
    BrowseDlgData.cchReturnPathLength = 255;
    BrowseDlgData.pCallBack = None;
    BrowseDlgData.dwCallBackArg = 0;
    BrowseDlgData.CallBackStatus = ERROR_SUCCESS as i32;
    BrowseDlgData.dwDefaultDetailLevel = PERF_DETAIL_WIZARD;
    BrowseDlgData.szDialogBoxCaption = text as *const _ as usize as *mut i8;
    let ret = PdhBrowseCountersA(&mut BrowseDlgData as *mut _);
    println!("browser: {:?}", ret);
    for x in CounterPathBuffer.iter() {
        print!("{:?} ", *x);
    }
    println!("");
    for x in 0..256 {
        print!("{:?} ", *BrowseDlgData.szReturnPathBuffer.offset(x));
    }
    println!("");
}*/

pub fn init_processors() -> Vec<Processor> {
    unsafe {
        let mut sys_info: SYSTEM_INFO = zeroed();
        GetSystemInfo(&mut sys_info);
        let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1);
        for nb in 0..sys_info.dwNumberOfProcessors {
            ret.push(create_processor(&format!("CPU {}", nb + 1)));
        }
        ret.insert(0, create_processor("Total CPU"));
        ret
    }
}

pub unsafe fn open_drive(drive_name: &[u16], open_rights: DWORD) -> HANDLE {
    CreateFileW(drive_name.as_ptr(),
                open_rights,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                ::std::ptr::null_mut(),
                OPEN_EXISTING,
                0,
                ::std::ptr::null_mut())
}

pub unsafe fn get_drive_size(handle: HANDLE) -> u64 {
    let mut pdg: DISK_GEOMETRY = ::std::mem::zeroed();
    let mut junk = 0;
    let result = DeviceIoControl(handle,
                                 IOCTL_DISK_GET_DRIVE_GEOMETRY,
                                 ::std::ptr::null_mut(),
                                 0,
                                 &mut pdg as *mut DISK_GEOMETRY as *mut c_void,
                                 size_of::<DISK_GEOMETRY>() as DWORD,
                                 &mut junk,
                                 ::std::ptr::null_mut());
    if result == TRUE {
        *pdg.Cylinders.QuadPart() as u64 * pdg.TracksPerCylinder as u64
        * pdg.SectorsPerTrack as u64 * pdg.BytesPerSector as u64
    } else {
        0
    }
}

pub unsafe fn get_disks() -> Vec<Disk> {
    let mut disks = Vec::new();
    let drives = GetLogicalDrives();
    if drives == 0 {
        return disks;
    }
    for x in 0..size_of::<DWORD>() * 8 {
        if (drives >> x) & 1 == 0 {
            continue
        }
        let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0];
        if GetDriveTypeW(mount_point.as_ptr()) != DRIVE_FIXED {
            continue
        }
        let mut name = [0u16; MAX_PATH + 1];
        let mut file_system = [0u16; 32];
        if GetVolumeInformationW(mount_point.as_ptr(),
                                 name.as_mut_ptr(),
                                 name.len() as DWORD,
                                 ::std::ptr::null_mut(),
                                 ::std::ptr::null_mut(),
                                 ::std::ptr::null_mut(),
                                 file_system.as_mut_ptr(),
                                 file_system.len() as DWORD) == 0 {
            continue
        }
        let mut pos = 0;
        for x in name.iter() {
            if *x == 0 {
                break
            }
            pos += 1;
        }
        let name = String::from_utf16_lossy(&name[..pos]);
        let name = OsStr::new(&name);

        pos = 0;
        for x in file_system.iter() {
            if *x == 0 {
                break
            }
            pos += 1;
        }
        let file_system: Vec<u8> = file_system[..pos].iter().map(|x| *x as u8).collect();

        let drive_name = [b'\\' as u16, b'\\' as u16, b'.' as u16, b'\\' as u16, b'A' as u16 + x as u16, b':' as u16, 0];
        let handle = open_drive(&drive_name, 0);
        if handle == INVALID_HANDLE_VALUE {
            disks.push(new_disk(name, &mount_point, &file_system, DiskType::Unknown(-1), 0));
            CloseHandle(handle);
            continue
        }
        let disk_size = get_drive_size(handle);
        /*let mut spq_trim: ffi::STORAGE_PROPERTY_QUERY = ::std::mem::zeroed();
        spq_trim.PropertyId = ffi::StorageDeviceTrimProperty;
        spq_trim.QueryType = ffi::PropertyStandardQuery;
        let mut dtd: ffi::DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();*/
        #[allow(non_snake_case)]
        #[repr(C)]
        struct STORAGE_PROPERTY_QUERY {
            PropertyId: i32,
            QueryType: i32,
            AdditionalParameters: [BYTE; 1]
        }
        #[allow(non_snake_case)]
        #[repr(C)]
        struct DEVICE_TRIM_DESCRIPTOR {
            Version: DWORD,
            Size: DWORD,
            TrimEnabled: BOOLEAN,
        }
        let mut spq_trim = STORAGE_PROPERTY_QUERY {
            PropertyId: 8i32,
            QueryType: 0i32,
            AdditionalParameters: [0],
        };
        let mut dtd: DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();

        let mut dw_size = 0;
        if DeviceIoControl(handle,
                           IOCTL_STORAGE_QUERY_PROPERTY,
                           &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void,
                           size_of::<STORAGE_PROPERTY_QUERY>() as DWORD,
                           &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void,
                           size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD,
                           &mut dw_size,
                           ::std::ptr::null_mut()) == 0 ||
           dw_size != size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD {
            disks.push(new_disk(name, &mount_point, &file_system, DiskType::Unknown(-1),
                                disk_size));
            CloseHandle(handle);
            continue
        }
        let is_ssd = dtd.TrimEnabled != 0;
        CloseHandle(handle);
        disks.push(new_disk(name, &mount_point, &file_system,
                            if is_ssd { DiskType::SSD } else { DiskType::HDD },
                            disk_size));
    }
    disks
}

#[allow(non_snake_case)]
pub unsafe fn load_symbols() -> HashMap<String, u32> {
    use winapi::um::winreg::{HKEY_PERFORMANCE_DATA, RegQueryValueExA};

    let mut cbCounters = 0;
    let mut dwType = 0;
    let mut ret = HashMap::new();

    let _dwStatus = RegQueryValueExA(HKEY_PERFORMANCE_DATA,
                                     b"Counter 009\0".as_ptr() as *const _,
                                     ::std::ptr::null_mut(),
                                     &mut dwType as *mut i32 as *mut _,
                                     ::std::ptr::null_mut(),
                                     &mut cbCounters as *mut i32 as *mut _);

    let mut lpmszCounters = Vec::with_capacity(cbCounters as usize);
    lpmszCounters.set_len(cbCounters as usize);
    let _dwStatus = RegQueryValueExA(HKEY_PERFORMANCE_DATA,
                                     b"Counter 009\0".as_ptr() as *const _,
                                     ::std::ptr::null_mut(),
                                     &mut dwType as *mut i32 as *mut _,
                                     lpmszCounters.as_mut_ptr(),
                                     &mut cbCounters as *mut i32 as *mut _);

    for (pos, s) in lpmszCounters.split(|x| *x == 0)
                                 .collect::<Vec<_>>()
                                 .chunks(2)
                                 .filter(|&x| x.len() == 2 && !x[0].is_empty() && !x[1].is_empty())
                                 .map(|x| (u32::from_str_radix(String::from_utf8(x[0].to_vec()).unwrap().as_str(), 10).unwrap(), String::from_utf8(x[1].to_vec()).expect("invalid string"))) {
        ret.insert(s, pos as u32);
    }
    ret
}

pub fn get_translation(s: &String, map: &HashMap<String, u32>) -> Option<String> {
    use winapi::um::pdh::PdhLookupPerfNameByIndexW;

    if let Some(index) = map.get(s) {
        let mut size: usize = 0;
        unsafe {
            let _res = PdhLookupPerfNameByIndexW(::std::ptr::null(),
                                                *index,
                                                ::std::ptr::null_mut(),
                                                &mut size as *mut usize as *mut _);
            if size == 0 {
                return Some(String::new());
            }
            else {
                let mut v = Vec::with_capacity(size);
                v.set_len(size);
                let _res = PdhLookupPerfNameByIndexW(::std::ptr::null(),
                                                    *index,
                                                    v.as_mut_ptr() as *mut _,
                                                    &mut size as *mut usize as *mut _);
                return Some(String::from_utf16(&v[..size - 1]).expect("invalid utf16"));
            }
        }
    }
    None
}

pub fn add_counter(s: String, query: &mut Query, keys: &mut Option<KeyHandler>, counter_name: String,
               value: CounterValue) {
    let mut full = s.encode_utf16().collect::<Vec<_>>();
    full.push(0);
    if query.add_counter(&counter_name, full.clone(), value) {
        *keys = Some(KeyHandler::new(counter_name, full));
    }
}

pub fn get_uptime() -> u64 {
    unsafe { GetTickCount64() / 1000 }
}
<commit_msg>Fix windows load_symbols failure<commit_after>//
// Sysinfo
//
// Copyright (c) 2018 Guillaume Gomez
//

use windows::processor::{create_processor, CounterValue, Processor, Query};

use sys::disk::{new_disk, Disk, DiskType};

use std::collections::HashMap;
use std::ffi::OsStr;
use std::mem::{size_of, zeroed};

use winapi::ctypes::c_void;

use winapi::shared::minwindef::{BYTE, DWORD, MAX_PATH, TRUE};
use winapi::um::fileapi::{
    CreateFileW, GetDriveTypeW, GetLogicalDrives, GetVolumeInformationW, OPEN_EXISTING,
};
use winapi::um::handleapi::CloseHandle;
use winapi::um::ioapiset::DeviceIoControl;
use winapi::um::handleapi::INVALID_HANDLE_VALUE;
use winapi::um::sysinfoapi::{
    GetSystemInfo, GetTickCount64, SYSTEM_INFO,
};
use winapi::um::winioctl::{
    DISK_GEOMETRY, IOCTL_STORAGE_QUERY_PROPERTY, IOCTL_DISK_GET_DRIVE_GEOMETRY,
};
use winapi::um::winnt::{
    BOOLEAN, FILE_SHARE_READ, FILE_SHARE_WRITE, HANDLE,
};
use winapi::um::winbase::DRIVE_FIXED;

pub struct KeyHandler {
    pub unique_id: String,
    pub win_key: Vec<u16>,
}

impl KeyHandler {
    pub fn new(unique_id: String, win_key: Vec<u16>) -> KeyHandler {
        KeyHandler {
            unique_id: unique_id,
            win_key: win_key,
        }
    }
}

/*#[allow(non_snake_case)]
#[allow(unused)]
unsafe fn browser() {
    use winapi::um::pdh::{PdhBrowseCountersA, PDH_BROWSE_DLG_CONFIG_A};
    use winapi::shared::winerror::ERROR_SUCCESS;

    let mut BrowseDlgData: PDH_BROWSE_DLG_CONFIG_A = ::std::mem::zeroed();
    let mut CounterPathBuffer: [i8; 255] = ::std::mem::zeroed();
    const PERF_DETAIL_WIZARD: u32 = 400;
    let text = b"Select a counter to monitor.\0";

    BrowseDlgData.set_IncludeInstanceIndex(FALSE as u32);
    BrowseDlgData.set_SingleCounterPerAdd(TRUE as u32);
    BrowseDlgData.set_SingleCounterPerDialog(TRUE as u32);
    BrowseDlgData.set_LocalCountersOnly(FALSE as u32);
    BrowseDlgData.set_WildCardInstances(TRUE as u32);
    BrowseDlgData.set_HideDetailBox(TRUE as u32);
    BrowseDlgData.set_InitializePath(FALSE as u32);
    BrowseDlgData.set_DisableMachineSelection(FALSE as u32);
    BrowseDlgData.set_IncludeCostlyObjects(FALSE as u32);
    BrowseDlgData.set_ShowObjectBrowser(FALSE as u32);
    BrowseDlgData.hWndOwner = ::std::ptr::null_mut();
    BrowseDlgData.szReturnPathBuffer = CounterPathBuffer.as_mut_ptr();
    BrowseDlgData.cchReturnPathLength = 255;
    BrowseDlgData.pCallBack = None;
    BrowseDlgData.dwCallBackArg = 0;
    BrowseDlgData.CallBackStatus = ERROR_SUCCESS as i32;
    BrowseDlgData.dwDefaultDetailLevel = PERF_DETAIL_WIZARD;
    BrowseDlgData.szDialogBoxCaption = text as *const _ as usize as *mut i8;
    let ret = PdhBrowseCountersA(&mut BrowseDlgData as *mut _);
    println!("browser: {:?}", ret);
    for x in CounterPathBuffer.iter() {
        print!("{:?} ", *x);
    }
    println!("");
    for x in 0..256 {
        print!("{:?} ", *BrowseDlgData.szReturnPathBuffer.offset(x));
    }
    println!("");
}*/

pub fn init_processors() -> Vec<Processor> {
    unsafe {
        let mut sys_info: SYSTEM_INFO = zeroed();
        GetSystemInfo(&mut sys_info);
        let mut ret = Vec::with_capacity(sys_info.dwNumberOfProcessors as usize + 1);
        for nb in 0..sys_info.dwNumberOfProcessors {
            ret.push(create_processor(&format!("CPU {}", nb + 1)));
        }
        ret.insert(0, create_processor("Total CPU"));
        ret
    }
}

pub unsafe fn open_drive(drive_name: &[u16], open_rights: DWORD) -> HANDLE {
    CreateFileW(drive_name.as_ptr(),
                open_rights,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                ::std::ptr::null_mut(),
                OPEN_EXISTING,
                0,
                ::std::ptr::null_mut())
}

pub unsafe fn get_drive_size(handle: HANDLE) -> u64 {
    let mut pdg: DISK_GEOMETRY = ::std::mem::zeroed();
    let mut junk = 0;
    let result = DeviceIoControl(handle,
                                 IOCTL_DISK_GET_DRIVE_GEOMETRY,
                                 ::std::ptr::null_mut(),
                                 0,
                                 &mut pdg as *mut DISK_GEOMETRY as *mut c_void,
                                 size_of::<DISK_GEOMETRY>() as DWORD,
                                 &mut junk,
                                 ::std::ptr::null_mut());
    if result == TRUE {
        *pdg.Cylinders.QuadPart() as u64 * pdg.TracksPerCylinder as u64
        * pdg.SectorsPerTrack as u64 * pdg.BytesPerSector as u64
    } else {
        0
    }
}

pub unsafe fn get_disks() -> Vec<Disk> {
    let mut disks = Vec::new();
    let drives = GetLogicalDrives();
    if drives == 0 {
        return disks;
    }
    for x in 0..size_of::<DWORD>() * 8 {
        if (drives >> x) & 1 == 0 {
            continue
        }
        let mount_point = [b'A' as u16 + x as u16, b':' as u16, b'\\' as u16, 0];
        if GetDriveTypeW(mount_point.as_ptr()) != DRIVE_FIXED {
            continue
        }
        let mut name = [0u16; MAX_PATH + 1];
        let mut file_system = [0u16; 32];
        if GetVolumeInformationW(mount_point.as_ptr(),
                                 name.as_mut_ptr(),
                                 name.len() as DWORD,
                                 ::std::ptr::null_mut(),
                                 ::std::ptr::null_mut(),
                                 ::std::ptr::null_mut(),
                                 file_system.as_mut_ptr(),
                                 file_system.len() as DWORD) == 0 {
            continue
        }
        let mut pos = 0;
        for x in name.iter() {
            if *x == 0 {
                break
            }
            pos += 1;
        }
        let name = String::from_utf16_lossy(&name[..pos]);
        let name = OsStr::new(&name);

        pos = 0;
        for x in file_system.iter() {
            if *x == 0 {
                break
            }
            pos += 1;
        }
        let file_system: Vec<u8> = file_system[..pos].iter().map(|x| *x as u8).collect();

        let drive_name = [b'\\' as u16, b'\\' as u16, b'.' as u16, b'\\' as u16, b'A' as u16 + x as u16, b':' as u16, 0];
        let handle = open_drive(&drive_name, 0);
        if handle == INVALID_HANDLE_VALUE {
            disks.push(new_disk(name, &mount_point, &file_system, DiskType::Unknown(-1), 0));
            CloseHandle(handle);
            continue
        }
        let disk_size = get_drive_size(handle);
        /*let mut spq_trim: ffi::STORAGE_PROPERTY_QUERY = ::std::mem::zeroed();
        spq_trim.PropertyId = ffi::StorageDeviceTrimProperty;
        spq_trim.QueryType = ffi::PropertyStandardQuery;
        let mut dtd: ffi::DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();*/
        #[allow(non_snake_case)]
        #[repr(C)]
        struct STORAGE_PROPERTY_QUERY {
            PropertyId: i32,
            QueryType: i32,
            AdditionalParameters: [BYTE; 1]
        }
        #[allow(non_snake_case)]
        #[repr(C)]
        struct DEVICE_TRIM_DESCRIPTOR {
            Version: DWORD,
            Size: DWORD,
            TrimEnabled: BOOLEAN,
        }
        let mut spq_trim = STORAGE_PROPERTY_QUERY {
            PropertyId: 8i32,
            QueryType: 0i32,
            AdditionalParameters: [0],
        };
        let mut dtd: DEVICE_TRIM_DESCRIPTOR = ::std::mem::zeroed();

        let mut dw_size = 0;
        if DeviceIoControl(handle,
                           IOCTL_STORAGE_QUERY_PROPERTY,
                           &mut spq_trim as *mut STORAGE_PROPERTY_QUERY as *mut c_void,
                           size_of::<STORAGE_PROPERTY_QUERY>() as DWORD,
                           &mut dtd as *mut DEVICE_TRIM_DESCRIPTOR as *mut c_void,
                           size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD,
                           &mut dw_size,
                           ::std::ptr::null_mut()) == 0 ||
           dw_size != size_of::<DEVICE_TRIM_DESCRIPTOR>() as DWORD {
            disks.push(new_disk(name, &mount_point, &file_system, DiskType::Unknown(-1),
                                disk_size));
            CloseHandle(handle);
            continue
        }
        let is_ssd = dtd.TrimEnabled != 0;
        CloseHandle(handle);
        disks.push(new_disk(name, &mount_point, &file_system,
                            if is_ssd { DiskType::SSD } else { DiskType::HDD },
                            disk_size));
    }
    disks
}

#[allow(non_snake_case)]
pub unsafe fn load_symbols() -> HashMap<String, u32> {
    use winapi::um::winreg::{HKEY_PERFORMANCE_DATA, RegQueryValueExA};

    let mut cbCounters = 0;
    let mut dwType = 0;
    let mut ret = HashMap::new();

    let _dwStatus = RegQueryValueExA(HKEY_PERFORMANCE_DATA,
                                     b"Counter 009\0".as_ptr() as *const _,
                                     ::std::ptr::null_mut(),
                                     &mut dwType as *mut i32 as *mut _,
                                     ::std::ptr::null_mut(),
                                     &mut cbCounters as *mut i32 as *mut _);

    let mut lpmszCounters = Vec::with_capacity(cbCounters as usize);
    lpmszCounters.set_len(cbCounters as usize);
    let _dwStatus = RegQueryValueExA(HKEY_PERFORMANCE_DATA,
                                     b"Counter 009\0".as_ptr() as *const _,
                                     ::std::ptr::null_mut(),
                                     &mut dwType as *mut i32 as *mut _,
                                     lpmszCounters.as_mut_ptr(),
                                     &mut cbCounters as *mut i32 as *mut _);
    for (pos, s) in lpmszCounters.split(|x| *x == 0)
                                 .filter(|x| !x.is_empty())
                                 .collect::<Vec<_>>()
                                 .chunks(2)
                                 .filter(|&x| x.len() == 2)
                                 .filter_map(|x| {
        match (std::str::from_utf8(x[0]), String::from_utf8(x[1].to_vec())) {
            (Ok(n), Ok(s)) => {
                if let Ok(n) = u32::from_str_radix(n, 10) {
                    Some((n, s))
                } else {
                    None
                }
            }
            _ => None,
        }
    }) {
        ret.insert(s, pos as u32);
    }
    ret
}

pub fn get_translation(s: &String, map: &HashMap<String, u32>) -> Option<String> {
    use winapi::um::pdh::PdhLookupPerfNameByIndexW;

    if let Some(index) = map.get(s) {
        let mut size: usize = 0;
        unsafe {
            let _res = PdhLookupPerfNameByIndexW(::std::ptr::null(),
                                                *index,
                                                ::std::ptr::null_mut(),
                                                &mut size as *mut usize as *mut _);
            if size == 0 {
                return Some(String::new());
            }
            else {
                let mut v = Vec::with_capacity(size);
                v.set_len(size);
                let _res = PdhLookupPerfNameByIndexW(::std::ptr::null(),
                                                    *index,
                                                    v.as_mut_ptr() as *mut _,
                                                    &mut size as *mut usize as *mut _);
                return Some(String::from_utf16(&v[..size - 1]).expect("invalid utf16"));
            }
        }
    }
    None
}

pub fn add_counter(s: String, query: &mut Query, keys: &mut Option<KeyHandler>, counter_name: String,
               value: CounterValue) {
    let mut full = s.encode_utf16().collect::<Vec<_>>();
    full.push(0);
    if query.add_counter(&counter_name, full.clone(), value) {
        *keys = Some(KeyHandler::new(counter_name, full));
    }
}

pub fn get_uptime() -> u64 {
    unsafe { GetTickCount64() / 1000 }
}
<|endoftext|>


<commit_before>extern crate core;
use core::iter::FromIterator;

pub fn anagrams_for<'a>(base_string: &str, candidates: &[&'a str]) -> Vec<&'a str> {
    let base_length = base_string.len();
    let filtered_candidates = candidates.iter()
        .filter(|candidate| candidate.len() == base_length)
        .filter(|candidate| is_not_same_word(base_string, candidate))
        .filter(|candidate| has_all_letters(base_string, candidate))
        .map(|&candidate| candidate);
    Vec::from_iter(filtered_candidates)
}

fn is_not_same_word(lhs: &str, rhs: &str) -> bool {
    lhs != rhs
}

fn has_all_letters(base: &str, candidate: &str) -> bool {
    let mut available_letters = Vec::from_iter(candidate.chars());
    for letter in base.chars() {
        let position = available_letters.iter()
            .position(|&tested_letter| tested_letter == letter);

        if position.is_none() {
            return false;
        }

        available_letters.remove(position.unwrap());
    }
    true
}
<commit_msg>case-insensitivy working<commit_after>extern crate core;
use core::iter::FromIterator;

pub fn anagrams_for<'a>(base_string: &str, candidates: &[&'a str]) -> Vec<&'a str> {
    let base_length = base_string.len();
    let filtered_candidates = candidates.iter()
        .filter(|candidate| candidate.len() == base_length)
        .filter(|candidate| is_not_same_word(base_string, candidate))
        .filter(|candidate| has_all_letters(base_string, candidate))
        .map(|&candidate| candidate);
    Vec::from_iter(filtered_candidates)
}

fn is_not_same_word(lhs: &str, rhs: &str) -> bool {
    lhs.to_lowercase() != rhs.to_lowercase()
}

fn has_all_letters(base: &str, candidate: &str) -> bool {
    let mut available_letters = Vec::from_iter(candidate.to_lowercase().chars());
    for letter in base.to_lowercase().chars() {
        let position = available_letters.iter()
            .position(|&tested_letter| tested_letter == letter);

        if position.is_none() {
            return false;
        }

        available_letters.remove(position.unwrap());
    }
    true
}
<|endoftext|>


<commit_before>use std::{
    collections::BTreeMap,
    fs,
    path::{Path, PathBuf},
};

use defaults::Defaults;
use eyre::{bail, Result};
use futures::future;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use tokio::sync::mpsc;

use files::{File, Files};
use graph_triples::{
    relations::{self, NULL_RANGE},
    resources, Resource, Triple,
};
use providers::provider::{ImportOptions, SyncOptions, WatchMode};
use stencila_schema::Node;

/// A source-destination combination
///
/// Each source by destination combination should be unique to a project.
/// It is possible to have the same source being imported to multiple
/// destinations within a project and for multiple sources to used the same
/// destination (e.g. the root directory of the project).
#[skip_serializing_none]
#[derive(Clone, Debug, Defaults, Deserialize, Serialize)]
#[serde(default)]
pub struct Source {
    /// The name of the source
    ///
    /// Useful for providing a shorthand way to refer to the source rather than using it's URL
    pub name: Option<String>,

    /// The URL of the source
    pub url: String,

    /// The providers that matched the URL
    pub provider: Option<String>,

    /// The node parsed from the URL by the provider
    pub node: Option<Node>,

    /// The destination path within the project
    pub dest: Option<PathBuf>,

    /// Run a cron schedule to import and/or export the source
    pub cron: Option<SourceCron>,

    /// Synchronize the source
    pub watch: Option<SourceWatch>,

    /// The name of the secret required to access the source
    ///
    /// To improve the security of API access tokens, secrets are only ever read from
    /// environment variables. Source providers usually have a default secret name
    /// e.g. `GITHUB_TOKEN`. However, this field allows setting of custom secret names
    /// which may be necessary, for example, if a project uses two sources from the
    /// same provider, requiring different secrets.
    pub secret_name: Option<String>,

    /// A list of file paths currently associated with the source (relative to the project root)
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub files: Vec<PathBuf>,

    /// A running cron task
    #[serde(skip)]
    #[def = "None"]
    cron_task: Option<SourceTask>,

    /// A running watch task
    #[serde(skip)]
    #[def = "None"]
    watch_task: Option<SourceTask>,
}

#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SourceCron {
    /// The schedule on which to perform the action
    ///
    /// Can be a cron phrase (e.g. "every 10mins") or cron expression (e.g. "0 0 */10 * * *").
    schedule: String,

    /// The cron expression/s parsed from the `schedule`
    expressions: Vec<String>,

    /// The timezone parsed from the `schedule`
    timezone: String,

    /// The action to perform at each scheduled time
    action: Option<String>,
}

#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SourceWatch {
    /// The synchronization mode
    mode: Option<WatchMode>,
}

#[derive(Debug, Clone)]
struct SourceTask {
    /// The channel sender used to cancel the source task
    ///
    /// Note that if the source is dropped (ie. removed from a list of sources) with a running task
    /// then this canceller will be dropped and so the task will also end (an explicit `.send()`
    /// is not required).
    canceller: mpsc::Sender<()>,
}

impl Source {
    /// Create a new source
    pub async fn new(
        url: String,
        name: Option<String>,
        dest: Option<PathBuf>,
        cron: Option<String>,
        watch: Option<WatchMode>,
    ) -> Result<Source> {
        let (provider, node) = providers::resolve(&url).await?;

        let cron = if let Some(schedule) = cron {
            let (schedules, timezone) = cron_utils::parse(&schedule)?;
            let expressions = schedules
                .iter()
                .map(|schedule| schedule.to_string())
                .collect();
            let timezone = timezone.to_string();

            Some(SourceCron {
                schedule,
                expressions,
                timezone,
                action: None,
            })
        } else {
            None
        };

        let watch = watch.map(|mode| SourceWatch { mode: Some(mode) });

        Ok(Source {
            name,
            url,
            provider: Some(provider),
            node: Some(node),
            dest,
            cron,
            watch,
            ..Default::default()
        })
    }

    /// Generate a label for the source
    pub fn label(&self) -> String {
        self.name.clone().unwrap_or_else(|| self.url.clone())
    }

    /// Does the source match a string identifier
    ///
    /// Matches the string against the `name`, the `url` , or the filename (of the `dest` with or without extension).
    pub fn matches(&self, identifier: &str) -> bool {
        if let Some(name) = &self.name {
            if name == identifier {
                return true;
            }
        }

        if identifier == self.url {
            return true;
        }

        if let Some(dest) = &self.dest {
            if dest.to_string_lossy() == identifier {
                return true;
            }
            if let Some(file_stem) = dest.file_stem() {
                if file_stem == identifier {
                    return true;
                }
            }
        }

        false
    }

    /// Read a source from a JSON file
    ///
    /// Only changes the properties that are NOT saved in the project.json file.
    pub fn read<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
        let path = path.as_ref();
        if !path.exists() {
            bail!("Project source file does not exist: {}", path.display())
        }
        let path = path.canonicalize()?;

        let json = fs::read_to_string(path)?;
        let source: Source = serde_json::from_str(&json)?;
        self.files = source.files;

        Ok(())
    }

    /// Create a graph resource for the source
    pub fn resource(&self) -> Resource {
        resources::url(&self.url)
    }

    /// Create a set of graph triples describing relation between the source it's associated files.
    pub fn triples(&self, project: &Path) -> Vec<Triple> {
        let this = self.resource();
        self.files
            .iter()
            .map(|file| {
                (
                    this.clone(),
                    relations::imports(NULL_RANGE),
                    resources::file(&project.join(file)),
                )
            })
            .collect()
    }

    /// Import the source
    ///
    /// # Arguments
    ///
    /// - `path`: The path to import the source into
    ///
    /// # Returns
    ///
    /// A map of the [`File`]s that were imported by the source.
    pub async fn import(&self, path: &Path) -> Result<BTreeMap<PathBuf, File>> {
        let (.., node) = providers::resolve(&self.url).await?;
        let dest = match &self.dest {
            Some(dest) => path.join(dest),
            None => path.to_path_buf(),
        };
        let options = ImportOptions {
            secret_name: self.secret_name.clone(),
        };

        let (pre, ..) = Files::walk(path, false);

        providers::import(&node, &dest, Some(options)).await?;

        let (post, ..) = Files::walk(path, false);
        let files = post
            .into_iter()
            .filter_map(|(path, file)| match pre.get(&path) {
                None => Some((path, file)),
                Some(existing) => {
                    if existing.size != file.size && existing.modified != file.modified {
                        Some((path, file))
                    } else {
                        None
                    }
                }
            });

        Ok(files.collect())
    }

    /// Start cron and watch tasks (as applicable and as needed) for the source
    pub async fn start(&mut self, dest: &Path) -> Result<()> {
        self.cron_task_start(dest).await?;
        self.watch_task_start(dest).await?;

        Ok(())
    }

    /// Start a background cron task for the source
    ///
    /// A task has a `cron` spec and there is no tasks currently running for it.
    pub async fn cron_task_start(&mut self, dest: &Path) -> Result<()> {
        let cron = match (&self.cron, &self.cron_task) {
            (Some(cron), None) => cron,
            _ => return Ok(()),
        };

        tracing::info!("Starting cron task for source `{}`", self.label());
        let action = cron.action.clone().unwrap_or_default();
        let schedule = cron.schedule.clone();
        let (.., node) = providers::resolve(&self.url).await?;
        let dest = dest.to_path_buf();
        let (canceller, cancellee) = mpsc::channel(1);
        tokio::spawn(
            async move { providers::cron(&action, &schedule, &node, &dest, cancellee).await },
        );
        self.cron_task = Some(SourceTask { canceller });

        Ok(())
    }

    /// Start a background watch task for the source
    ///
    /// A task has a `watch` spec and there is no tasks currently running for it.
    pub async fn watch_task_start(&mut self, dest: &Path) -> Result<()> {
        let watch = match (&self.watch, &self.watch_task) {
            (Some(watch), None) => watch,
            _ => return Ok(()),
        };

        tracing::info!("Starting watch task for source `{}`", self.label());
        let (.., node) = providers::resolve(&self.url).await?;
        let dest = dest.to_path_buf();
        let (canceller, cancellee) = mpsc::channel(1);
        let options = SyncOptions {
            mode: watch.mode.clone(),
            secret_name: self.secret_name.clone(),
            ..Default::default()
        };
        tokio::spawn(async move { providers::watch(&node, &dest, cancellee, Some(options)).await });
        self.watch_task = Some(SourceTask { canceller });

        Ok(())
    }

    /// Start cron and watch tasks (if started) for the source
    pub async fn stop(&mut self) -> Result<()> {
        if let Some(task) = &self.cron_task {
            tracing::info!("Stopping cron task for source `{}`", self.label());
            task.canceller.send(()).await?
        }
        self.cron_task = None;

        if let Some(task) = &self.watch_task {
            tracing::info!("Stopping watch task for source `{}`", self.label());
            task.canceller.send(()).await?
        }
        self.watch_task = None;

        Ok(())
    }
}

/// A set of sources, usually associated with a project
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
#[serde(transparent)]
pub struct Sources {
    /// The list of sources
    pub inner: Vec<Source>,

    /// If in a running state, the path that cron and watch tasks were started with
    ///
    /// If tasks are running then any new sources that are added will have
    /// tasks automatically started for them.
    #[serde(skip)]
    running: Option<PathBuf>,
}

impl Sources {
    /// Return a list of sources
    pub fn list(&self) -> Vec<String> {
        self.inner.iter().map(|source| source.label()).collect()
    }

    /// Find a source
    ///
    /// # Arguments
    ///
    /// - `identifier`: An identifier for a source.
    ///
    /// The first source that matches the identifier is returned. Will error if no match is found.
    pub fn find(&self, identifier: &str) -> Result<&Source> {
        if let Some(source) = self.inner.iter().find(|source| source.matches(identifier)) {
            return Ok(source);
        }

        bail!("Unable to find a source matching `{}`", identifier)
    }

    /// Add a source
    ///
    /// # Arguments
    ///
    /// - `source`: The source to add
    ///
    /// Warns if there is already a source with the same `url`.
    /// Errors if there is already a source with the same `name` or the same `url` and `dest`.
    ///
    /// If the `start` method has been called previously then the sources are in a "running"
    /// state and the `start` will be called on the source.
    pub async fn add(&mut self, mut source: Source) -> Result<()> {
        let source_dest = source.dest.clone().unwrap_or_else(|| PathBuf::from("."));
        for existing in self.inner.iter() {
            if let (Some(existing_name), Some(source_name)) = (&existing.name, &source.name) {
                if existing_name == source_name {
                    bail!("There is already a source with the name `{}`", source_name);
                }
            }
            let existing_dest = existing.dest.clone().unwrap_or_else(|| PathBuf::from("."));
            if existing.url == source.url && existing_dest == source_dest {
                bail!(
                    "There is already a source with the URL `{}` and destination `{}`",
                    source.url,
                    source_dest.display()
                );
            }
            if existing.url == source.url {
                tracing::warn!("There is already a source with the URL `{}`", source.url);
            }
        }
        if let Some(path) = &self.running {
            source.start(path).await?;
        }
        self.inner.push(source);

        Ok(())
    }

    /// Remove a source
    ///
    /// # Arguments
    ///
    /// - `identifier`: An identifier for a source.
    ///
    /// Any running tasks for the source will be stopped.
    ///
    /// The first source that matches the identifier is removed. See [`Source::matches`] for
    /// details. Will error if no match is found.
    pub async fn remove(&mut self, identifier: &str) -> Result<Source> {
        if let Some(index) = self
            .inner
            .iter()
            .position(|source| source.matches(identifier))
        {
            let mut removed = self.inner.remove(index);
            removed.stop().await?;
            return Ok(removed);
        }

        bail!("Unable to find a matching source to remove")
    }

    /// Import all sources
    ///
    /// # Arguments
    ///
    /// - `path`: The path to import the sources into (usually a project directory)
    ///
    /// Imports sources in parallel.
    pub async fn import(&self, path: &Path) -> Result<()> {
        let futures = self.inner.iter().map(|source| {
            let source = source.clone();
            let path = path.to_path_buf();
            tokio::spawn(async move { source.import(&path).await })
        });
        future::try_join_all(futures).await?;

        Ok(())
    }

    /// Start cron and/or watch tasks for each source
    pub async fn start(&mut self, path: &Path) -> Result<()> {
        for source in self.inner.iter_mut() {
            let dest = match &source.dest {
                Some(dest) => path.join(dest),
                None => path.to_path_buf(),
            };
            source.start(&dest).await?;
        }
        self.running = Some(path.to_path_buf());

        Ok(())
    }

    /// Stop any cron or watch tasks for each source
    pub async fn stop(&mut self) -> Result<()> {
        for source in self.inner.iter_mut() {
            source.stop().await?;
        }
        self.running = None;

        Ok(())
    }
}
<commit_msg>refactor(Sources): fix(Sources): Make derived `expressions` and `timezone` fields optional<commit_after>use std::{
    collections::BTreeMap,
    fs,
    path::{Path, PathBuf},
};

use defaults::Defaults;
use eyre::{bail, Result};
use futures::future;
use serde::{Deserialize, Serialize};
use serde_with::skip_serializing_none;
use tokio::sync::mpsc;

use files::{File, Files};
use graph_triples::{
    relations::{self, NULL_RANGE},
    resources, Resource, Triple,
};
use providers::provider::{ImportOptions, SyncOptions, WatchMode};
use stencila_schema::Node;

/// A source-destination combination
///
/// Each source by destination combination should be unique to a project.
/// It is possible to have the same source being imported to multiple
/// destinations within a project and for multiple sources to used the same
/// destination (e.g. the root directory of the project).
#[skip_serializing_none]
#[derive(Clone, Debug, Defaults, Deserialize, Serialize)]
#[serde(default)]
pub struct Source {
    /// The name of the source
    ///
    /// Useful for providing a shorthand way to refer to the source rather than using it's URL
    pub name: Option<String>,

    /// The URL of the source
    pub url: String,

    /// The providers that matched the URL
    pub provider: Option<String>,

    /// The node parsed from the URL by the provider
    pub node: Option<Node>,

    /// The destination path within the project
    pub dest: Option<PathBuf>,

    /// Run a cron schedule to import and/or export the source
    pub cron: Option<SourceCron>,

    /// Synchronize the source
    pub watch: Option<SourceWatch>,

    /// The name of the secret required to access the source
    ///
    /// To improve the security of API access tokens, secrets are only ever read from
    /// environment variables. Source providers usually have a default secret name
    /// e.g. `GITHUB_TOKEN`. However, this field allows setting of custom secret names
    /// which may be necessary, for example, if a project uses two sources from the
    /// same provider, requiring different secrets.
    pub secret_name: Option<String>,

    /// A list of file paths currently associated with the source (relative to the project root)
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub files: Vec<PathBuf>,

    /// A running cron task
    #[serde(skip)]
    #[def = "None"]
    cron_task: Option<SourceTask>,

    /// A running watch task
    #[serde(skip)]
    #[def = "None"]
    watch_task: Option<SourceTask>,
}

#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SourceCron {
    /// The schedule on which to perform the action
    ///
    /// Can be a cron phrase (e.g. "every 10mins") or cron expression (e.g. "0 0 */10 * * *").
    schedule: String,

    /// The cron expression/s parsed from the `schedule`
    expressions: Option<Vec<String>>,

    /// The timezone parsed from the `schedule`
    timezone: Option<String>,

    /// The action to perform at each scheduled time
    action: Option<String>,
}

#[skip_serializing_none]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct SourceWatch {
    /// The synchronization mode
    mode: Option<WatchMode>,
}

#[derive(Debug, Clone)]
struct SourceTask {
    /// The channel sender used to cancel the source task
    ///
    /// Note that if the source is dropped (ie. removed from a list of sources) with a running task
    /// then this canceller will be dropped and so the task will also end (an explicit `.send()`
    /// is not required).
    canceller: mpsc::Sender<()>,
}

impl Source {
    /// Create a new source
    pub async fn new(
        url: String,
        name: Option<String>,
        dest: Option<PathBuf>,
        cron: Option<String>,
        watch: Option<WatchMode>,
    ) -> Result<Source> {
        let (provider, node) = providers::resolve(&url).await?;

        let cron = if let Some(schedule) = cron {
            let (schedules, timezone) = cron_utils::parse(&schedule)?;
            let (expressions, timezone) = if !schedules.is_empty() {
                (
                    Some(
                        schedules
                            .iter()
                            .map(|schedule| schedule.to_string())
                            .collect(),
                    ),
                    Some(timezone.to_string()),
                )
            } else {
                (None, None)
            };

            Some(SourceCron {
                schedule,
                expressions,
                timezone,
                action: None,
            })
        } else {
            None
        };

        let watch = watch.map(|mode| SourceWatch { mode: Some(mode) });

        Ok(Source {
            name,
            url,
            provider: Some(provider),
            node: Some(node),
            dest,
            cron,
            watch,
            ..Default::default()
        })
    }

    /// Generate a label for the source
    pub fn label(&self) -> String {
        self.name.clone().unwrap_or_else(|| self.url.clone())
    }

    /// Does the source match a string identifier
    ///
    /// Matches the string against the `name`, the `url` , or the filename (of the `dest` with or without extension).
    pub fn matches(&self, identifier: &str) -> bool {
        if let Some(name) = &self.name {
            if name == identifier {
                return true;
            }
        }

        if identifier == self.url {
            return true;
        }

        if let Some(dest) = &self.dest {
            if dest.to_string_lossy() == identifier {
                return true;
            }
            if let Some(file_stem) = dest.file_stem() {
                if file_stem == identifier {
                    return true;
                }
            }
        }

        false
    }

    /// Read a source from a JSON file
    ///
    /// Only changes the properties that are NOT saved in the project.json file.
    pub fn read<P: AsRef<Path>>(&mut self, path: P) -> Result<()> {
        let path = path.as_ref();
        if !path.exists() {
            bail!("Project source file does not exist: {}", path.display())
        }
        let path = path.canonicalize()?;

        let json = fs::read_to_string(path)?;
        let source: Source = serde_json::from_str(&json)?;
        self.files = source.files;

        Ok(())
    }

    /// Create a graph resource for the source
    pub fn resource(&self) -> Resource {
        resources::url(&self.url)
    }

    /// Create a set of graph triples describing relation between the source it's associated files.
    pub fn triples(&self, project: &Path) -> Vec<Triple> {
        let this = self.resource();
        self.files
            .iter()
            .map(|file| {
                (
                    this.clone(),
                    relations::imports(NULL_RANGE),
                    resources::file(&project.join(file)),
                )
            })
            .collect()
    }

    /// Import the source
    ///
    /// # Arguments
    ///
    /// - `path`: The path to import the source into
    ///
    /// # Returns
    ///
    /// A map of the [`File`]s that were imported by the source.
    pub async fn import(&self, path: &Path) -> Result<BTreeMap<PathBuf, File>> {
        let (.., node) = providers::resolve(&self.url).await?;
        let dest = match &self.dest {
            Some(dest) => path.join(dest),
            None => path.to_path_buf(),
        };
        let options = ImportOptions {
            secret_name: self.secret_name.clone(),
        };

        let (pre, ..) = Files::walk(path, false);

        providers::import(&node, &dest, Some(options)).await?;

        let (post, ..) = Files::walk(path, false);
        let files = post
            .into_iter()
            .filter_map(|(path, file)| match pre.get(&path) {
                None => Some((path, file)),
                Some(existing) => {
                    if existing.size != file.size && existing.modified != file.modified {
                        Some((path, file))
                    } else {
                        None
                    }
                }
            });

        Ok(files.collect())
    }

    /// Start cron and watch tasks (as applicable and as needed) for the source
    pub async fn start(&mut self, dest: &Path) -> Result<()> {
        self.cron_task_start(dest).await?;
        self.watch_task_start(dest).await?;

        Ok(())
    }

    /// Start a background cron task for the source
    ///
    /// A task has a `cron` spec and there is no tasks currently running for it.
    pub async fn cron_task_start(&mut self, dest: &Path) -> Result<()> {
        let cron = match (&self.cron, &self.cron_task) {
            (Some(cron), None) => cron,
            _ => return Ok(()),
        };

        tracing::info!("Starting cron task for source `{}`", self.label());
        let action = cron.action.clone().unwrap_or_default();
        let schedule = cron.schedule.clone();
        let (.., node) = providers::resolve(&self.url).await?;
        let dest = dest.to_path_buf();
        let (canceller, cancellee) = mpsc::channel(1);
        tokio::spawn(
            async move { providers::cron(&action, &schedule, &node, &dest, cancellee).await },
        );
        self.cron_task = Some(SourceTask { canceller });

        Ok(())
    }

    /// Start a background watch task for the source
    ///
    /// A task has a `watch` spec and there is no tasks currently running for it.
    pub async fn watch_task_start(&mut self, dest: &Path) -> Result<()> {
        let watch = match (&self.watch, &self.watch_task) {
            (Some(watch), None) => watch,
            _ => return Ok(()),
        };

        tracing::info!("Starting watch task for source `{}`", self.label());
        let (.., node) = providers::resolve(&self.url).await?;
        let dest = dest.to_path_buf();
        let (canceller, cancellee) = mpsc::channel(1);
        let options = SyncOptions {
            mode: watch.mode.clone(),
            secret_name: self.secret_name.clone(),
            ..Default::default()
        };
        tokio::spawn(async move { providers::watch(&node, &dest, cancellee, Some(options)).await });
        self.watch_task = Some(SourceTask { canceller });

        Ok(())
    }

    /// Start cron and watch tasks (if started) for the source
    pub async fn stop(&mut self) -> Result<()> {
        if let Some(task) = &self.cron_task {
            tracing::info!("Stopping cron task for source `{}`", self.label());
            task.canceller.send(()).await?
        }
        self.cron_task = None;

        if let Some(task) = &self.watch_task {
            tracing::info!("Stopping watch task for source `{}`", self.label());
            task.canceller.send(()).await?
        }
        self.watch_task = None;

        Ok(())
    }
}

/// A set of sources, usually associated with a project
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
#[serde(transparent)]
pub struct Sources {
    /// The list of sources
    pub inner: Vec<Source>,

    /// If in a running state, the path that cron and watch tasks were started with
    ///
    /// If tasks are running then any new sources that are added will have
    /// tasks automatically started for them.
    #[serde(skip)]
    running: Option<PathBuf>,
}

impl Sources {
    /// Return a list of sources
    pub fn list(&self) -> Vec<String> {
        self.inner.iter().map(|source| source.label()).collect()
    }

    /// Find a source
    ///
    /// # Arguments
    ///
    /// - `identifier`: An identifier for a source.
    ///
    /// The first source that matches the identifier is returned. Will error if no match is found.
    pub fn find(&self, identifier: &str) -> Result<&Source> {
        if let Some(source) = self.inner.iter().find(|source| source.matches(identifier)) {
            return Ok(source);
        }

        bail!("Unable to find a source matching `{}`", identifier)
    }

    /// Add a source
    ///
    /// # Arguments
    ///
    /// - `source`: The source to add
    ///
    /// Warns if there is already a source with the same `url`.
    /// Errors if there is already a source with the same `name` or the same `url` and `dest`.
    ///
    /// If the `start` method has been called previously then the sources are in a "running"
    /// state and the `start` will be called on the source.
    pub async fn add(&mut self, mut source: Source) -> Result<()> {
        let source_dest = source.dest.clone().unwrap_or_else(|| PathBuf::from("."));
        for existing in self.inner.iter() {
            if let (Some(existing_name), Some(source_name)) = (&existing.name, &source.name) {
                if existing_name == source_name {
                    bail!("There is already a source with the name `{}`", source_name);
                }
            }
            let existing_dest = existing.dest.clone().unwrap_or_else(|| PathBuf::from("."));
            if existing.url == source.url && existing_dest == source_dest {
                bail!(
                    "There is already a source with the URL `{}` and destination `{}`",
                    source.url,
                    source_dest.display()
                );
            }
            if existing.url == source.url {
                tracing::warn!("There is already a source with the URL `{}`", source.url);
            }
        }
        if let Some(path) = &self.running {
            source.start(path).await?;
        }
        self.inner.push(source);

        Ok(())
    }

    /// Remove a source
    ///
    /// # Arguments
    ///
    /// - `identifier`: An identifier for a source.
    ///
    /// Any running tasks for the source will be stopped.
    ///
    /// The first source that matches the identifier is removed. See [`Source::matches`] for
    /// details. Will error if no match is found.
    pub async fn remove(&mut self, identifier: &str) -> Result<Source> {
        if let Some(index) = self
            .inner
            .iter()
            .position(|source| source.matches(identifier))
        {
            let mut removed = self.inner.remove(index);
            removed.stop().await?;
            return Ok(removed);
        }

        bail!("Unable to find a matching source to remove")
    }

    /// Import all sources
    ///
    /// # Arguments
    ///
    /// - `path`: The path to import the sources into (usually a project directory)
    ///
    /// Imports sources in parallel.
    pub async fn import(&self, path: &Path) -> Result<()> {
        let futures = self.inner.iter().map(|source| {
            let source = source.clone();
            let path = path.to_path_buf();
            tokio::spawn(async move { source.import(&path).await })
        });
        future::try_join_all(futures).await?;

        Ok(())
    }

    /// Start cron and/or watch tasks for each source
    pub async fn start(&mut self, path: &Path) -> Result<()> {
        for source in self.inner.iter_mut() {
            let dest = match &source.dest {
                Some(dest) => path.join(dest),
                None => path.to_path_buf(),
            };
            source.start(&dest).await?;
        }
        self.running = Some(path.to_path_buf());

        Ok(())
    }

    /// Stop any cron or watch tasks for each source
    pub async fn stop(&mut self) -> Result<()> {
        for source in self.inner.iter_mut() {
            source.stop().await?;
        }
        self.running = None;

        Ok(())
    }
}
<|endoftext|>