<commit_before>use eframe::egui;
use egui::emath::Vec2;

use std::fs::{self, File};
use std::io::Write;

use cubes_rs::Pieces;

fn main() {
    let options = eframe::NativeOptions {
        initial_window_size: Some(Vec2 { x: 180., y: 300. }),
        ..Default::default()
    };

    eframe::run_native(
        "Polycubes",
        options,
        Box::new(|_cc| Box::new(MyApp::default())),
    );
}

struct MyApp {
    name: String,
    cube: [[[bool; 3]; 3]; 3],
    pieces: Pieces,
}

impl Default for MyApp {
    fn default() -> Self {
        Self {
            name: "".to_owned(),
            cube: [[[false; 3]; 3]; 3],
            pieces: Pieces { data: Vec::new() },
        }
    }
}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("polycube piece");
            ui.horizontal(|ui| {
                ui.set_width(100.);
                ui.text_edit_singleline(&mut self.name);
            });

            for x in 0..3 {
                if x > 0 {
                    ui.horizontal(|ui| {
                        ui.label("");
                    });
                }
                for y in 0..3 {
                    ui.horizontal(|ui| {
                        for z in 0..3 {
                            if ui.toggle_value(&mut self.cube[x][y][z], "    ").clicked() {

                            }
                        }
                    });
                }
            }

            ui.horizontal(|ui| {
                if ui.button("save piece").clicked() {
                    self.pieces.data.push(Vec::new());
                    let len = self.pieces.data.len() - 1;

                    for x in 0..3 {
                        for y in 0..3 {
                            for z in 0..3 {
                                if self.cube[x][y][z] {
                                    println!("{:?} {:?} {:?}", x, y, z);
                                    self.pieces.data[len].push([x as i32, y as i32, z as i32]);
                                }
                            }
                        }
                    }
                    println!();
                }

                if ui.button("save all").clicked() {
                    println!("{}", ron::to_string(&self.pieces).unwrap());
                    println!();

                    let mut buffer = File::create(format!("puzzles/{}", self.name)).unwrap();
                    let encoded: Vec<u8> = bincode::serialize(&self.pieces).unwrap();
                    buffer.write_all(&encoded).unwrap();

                    let decoded: Pieces = bincode::deserialize(&fs::read(format!("puzzles/{}", self.name)).unwrap()).unwrap();
                    println!("{:?}", decoded);
                }
            });
        });
    }
}<commit_msg>Don't decode when encoding.<commit_after>use eframe::egui;
use egui::emath::Vec2;

use std::fs::File;
use std::io::Write;

use cubes_rs::Pieces;

fn main() {
    let options = eframe::NativeOptions {
        initial_window_size: Some(Vec2 { x: 180., y: 300. }),
        ..Default::default()
    };

    eframe::run_native(
        "Polycubes",
        options,
        Box::new(|_cc| Box::new(MyApp::default())),
    );
}

struct MyApp {
    name: String,
    cube: [[[bool; 3]; 3]; 3],
    pieces: Pieces,
}

impl Default for MyApp {
    fn default() -> Self {
        Self {
            name: "".to_owned(),
            cube: [[[false; 3]; 3]; 3],
            pieces: Pieces { data: Vec::new() },
        }
    }
}

impl eframe::App for MyApp {
    fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
        egui::CentralPanel::default().show(ctx, |ui| {
            ui.heading("polycube piece");
            ui.horizontal(|ui| {
                ui.set_width(100.);
                ui.text_edit_singleline(&mut self.name);
            });

            for x in 0..3 {
                if x > 0 {
                    ui.horizontal(|ui| {
                        ui.label("");
                    });
                }
                for y in 0..3 {
                    ui.horizontal(|ui| {
                        for z in 0..3 {
                            if ui.toggle_value(&mut self.cube[x][y][z], "    ").clicked() {

                            }
                        }
                    });
                }
            }

            ui.horizontal(|ui| {
                if ui.button("save piece").clicked() {
                    self.pieces.data.push(Vec::new());
                    let len = self.pieces.data.len() - 1;

                    for x in 0..3 {
                        for y in 0..3 {
                            for z in 0..3 {
                                if self.cube[x][y][z] {
                                    println!("{:?} {:?} {:?}", x, y, z);
                                    self.pieces.data[len].push([x as i32, y as i32, z as i32]);
                                }
                            }
                        }
                    }
                    println!();
                }

                if ui.button("save all").clicked() {
                    println!("{}", ron::to_string(&self.pieces).unwrap());
                    println!();

                    let mut buffer = File::create(format!("puzzles/{}", self.name)).unwrap();
                    let encoded: Vec<u8> = bincode::serialize(&self.pieces).unwrap();
                    buffer.write_all(&encoded).unwrap();
                }
            });
        });
    }
}<|endoftext|>


<commit_before>use core::cell::Cell;

use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn};
use libtock_unittest::{
    fake::{self, GpioMode, InterruptEdge, PullMode},
    upcall,
};

use crate::{GpioInterruptListener, GpioState, PullDown, PullNone, PullUp, DRIVER_NUM};

type Gpio = super::Gpio<fake::Syscalls>;

#[test]
fn no_driver() {
    let _kernel = fake::Kernel::new();
    assert_eq!(Gpio::count(), Err(ErrorCode::NoDevice));
}

#[test]
fn num_gpio() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    kernel.add_driver(&driver);
    assert_eq!(Gpio::count(), Ok(10));
}

// Tests the OutputPin implementation.
#[test]
fn output() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    let pin_11 = Gpio::get_pin(11);
    assert!(pin_11.is_err());
    let _ = pin_11.map_err(|error| assert_eq!(error, ErrorCode::Invalid));
    let pin_1 = Gpio::get_pin(1);
    assert!(pin_1.is_err());
    let _ = pin_1.map_err(|error| assert_eq!(error, ErrorCode::NoDevice));

    let pin_0 = Gpio::get_pin(0);
    assert!(pin_0.is_ok());

    let _ = pin_0.map(|mut pin| {
        let output_pin = pin.make_output();
        assert!(output_pin.is_ok());
        assert_eq!(driver.get_gpio_state(0).unwrap().mode, GpioMode::Output);
        let _ = output_pin.map(|mut pin| {
            assert_eq!(pin.set(), Ok(()));
            assert!(driver.get_gpio_state(0).unwrap().value);
            assert_eq!(pin.clear(), Ok(()));
            assert!(!driver.get_gpio_state(0).unwrap().value);
            assert_eq!(pin.toggle(), Ok(()));
            assert!(driver.get_gpio_state(0).unwrap().value);
            assert_eq!(pin.toggle(), Ok(()));
            assert!(!driver.get_gpio_state(0).unwrap().value);
        });
        assert_eq!(driver.get_gpio_state(0).unwrap().mode, GpioMode::Disable);
    });
}

// Tests the InputPin implementation
#[test]
fn input() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    let pin_11 = Gpio::get_pin(11);
    assert!(pin_11.is_err());
    let _ = pin_11.map_err(|error| assert_eq!(error, ErrorCode::Invalid));
    let pin_1 = Gpio::get_pin(1);
    assert!(pin_1.is_err());
    let _ = pin_1.map_err(|error| assert_eq!(error, ErrorCode::NoDevice));

    let pin_0 = Gpio::get_pin(0);
    assert!(pin_0.is_ok());

    let _ = pin_0.map(|pin| {
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let input_pin = pin.make_input::<PullUp>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullUp)
        );

        let input_pin = pin.make_input::<PullDown>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullDown)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(driver.set_value(0, true), Ok(()));
            assert_eq!(pin.read(), Ok(GpioState::High));
            assert_eq!(driver.set_value(0, false), Ok(()));
            assert_eq!(pin.read(), Ok(GpioState::Low));
        });
        assert_eq!(driver.get_gpio_state(0).unwrap().mode, GpioMode::Disable);
    });
}

// Tests the pin interrupts implementation
#[test]
fn interrupts() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    let gpio_state = Cell::<Option<GpioState>>::new(None);
    let listener = GpioInterruptListener(|gpio, state| {
        assert_eq!(gpio, 0);
        gpio_state.set(Some(state));
    });

    share::scope(|subscribe| {
        assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
        assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
        assert_eq!(gpio_state.get(), Some(GpioState::Low));
    });

    assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
    assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);

    let pin_11 = Gpio::get_pin(11);
    assert!(pin_11.is_err());
    let _ = pin_11.map_err(|error| assert_eq!(error, ErrorCode::Invalid));
    let pin_1 = Gpio::get_pin(1);
    assert!(pin_1.is_err());
    let _ = pin_1.map_err(|error| assert_eq!(error, ErrorCode::NoDevice));

    let pin_0 = Gpio::get_pin(0);
    assert!(pin_0.is_ok());

    let _ = pin_0.map(|pin| {
        // Either
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(
                pin.enable_interrupts(crate::PinInterruptEdge::Either),
                Ok(())
            );
            assert_eq!(
                driver.get_gpio_state(0).unwrap().interrupt_enabled,
                Some(InterruptEdge::Either)
            );

            assert_eq!(driver.set_value(0, false), Ok(()));

            let gpio_state = Cell::<Option<GpioState>>::new(None);
            let listener = GpioInterruptListener(|gpio, state| {
                assert_eq!(gpio, 0);
                gpio_state.set(Some(state));
            });

            share::scope(|subscribe| {
                assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::High));
                gpio_state.set(None);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::Low));

                assert_eq!(pin.disable_interrupts(), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
            });
        });

        // Rising
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(
                pin.enable_interrupts(crate::PinInterruptEdge::Rising),
                Ok(())
            );
            assert_eq!(
                driver.get_gpio_state(0).unwrap().interrupt_enabled,
                Some(InterruptEdge::Rising)
            );

            assert_eq!(driver.set_value(0, false), Ok(()));

            let gpio_state = Cell::<Option<GpioState>>::new(None);
            let listener = GpioInterruptListener(|gpio, state| {
                assert_eq!(gpio, 0);
                gpio_state.set(Some(state));
            });

            share::scope(|subscribe| {
                assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::High));
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);

                assert_eq!(pin.disable_interrupts(), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
            });
        });

        // Falling
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(
                pin.enable_interrupts(crate::PinInterruptEdge::Falling),
                Ok(())
            );
            assert_eq!(
                driver.get_gpio_state(0).unwrap().interrupt_enabled,
                Some(InterruptEdge::Falling)
            );

            assert_eq!(driver.set_value(0, false), Ok(()));

            let gpio_state = Cell::<Option<GpioState>>::new(None);
            let listener = GpioInterruptListener(|gpio, state| {
                assert_eq!(gpio, 0);
                gpio_state.set(Some(state));
            });

            share::scope(|subscribe| {
                assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::Low));

                assert_eq!(pin.disable_interrupts(), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
            });
        });
    });
}

// Tests the pin event subcribe implementation
#[test]
fn subscribe() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    let gpio_state = Cell::<Option<GpioState>>::new(None);
    let listener = GpioInterruptListener(|gpio, state| {
        assert_eq!(gpio, 0);
        gpio_state.set(Some(state));
    });

    share::scope(|subscribe| {
        assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
        assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
        assert_eq!(gpio_state.get(), Some(GpioState::Low));
    });

    assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
    assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
}
<commit_msg>use core::matches<commit_after>use core::cell::Cell;

use libtock_platform::{share, ErrorCode, Syscalls, YieldNoWaitReturn};
use libtock_unittest::{
    fake::{self, GpioMode, InterruptEdge, PullMode},
    upcall,
};

use crate::{GpioInterruptListener, GpioState, PullDown, PullNone, PullUp, DRIVER_NUM};

type Gpio = super::Gpio<fake::Syscalls>;

#[test]
fn no_driver() {
    let _kernel = fake::Kernel::new();
    assert_eq!(Gpio::count(), Err(ErrorCode::NoDevice));
}

#[test]
fn num_gpio() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    kernel.add_driver(&driver);
    assert_eq!(Gpio::count(), Ok(10));
}

// Tests the OutputPin implementation.
#[test]
fn output() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    assert!(core::matches!(Gpio::get_pin(11), Err(ErrorCode::Invalid)));
    assert!(core::matches!(Gpio::get_pin(1), Err(ErrorCode::NoDevice)));

    let pin_0 = Gpio::get_pin(0);
    assert!(pin_0.is_ok());

    let _ = pin_0.map(|mut pin| {
        let output_pin = pin.make_output();
        assert!(output_pin.is_ok());
        assert_eq!(driver.get_gpio_state(0).unwrap().mode, GpioMode::Output);
        let _ = output_pin.map(|mut pin| {
            assert_eq!(pin.set(), Ok(()));
            assert!(driver.get_gpio_state(0).unwrap().value);
            assert_eq!(pin.clear(), Ok(()));
            assert!(!driver.get_gpio_state(0).unwrap().value);
            assert_eq!(pin.toggle(), Ok(()));
            assert!(driver.get_gpio_state(0).unwrap().value);
            assert_eq!(pin.toggle(), Ok(()));
            assert!(!driver.get_gpio_state(0).unwrap().value);
        });
        assert_eq!(driver.get_gpio_state(0).unwrap().mode, GpioMode::Disable);
    });
}

// Tests the InputPin implementation
#[test]
fn input() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    assert!(core::matches!(Gpio::get_pin(11), Err(ErrorCode::Invalid)));
    assert!(core::matches!(Gpio::get_pin(1), Err(ErrorCode::NoDevice)));

    let pin_0 = Gpio::get_pin(0);
    assert!(pin_0.is_ok());

    let _ = pin_0.map(|pin| {
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let input_pin = pin.make_input::<PullUp>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullUp)
        );

        let input_pin = pin.make_input::<PullDown>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullDown)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(driver.set_value(0, true), Ok(()));
            assert_eq!(pin.read(), Ok(GpioState::High));
            assert_eq!(driver.set_value(0, false), Ok(()));
            assert_eq!(pin.read(), Ok(GpioState::Low));
        });
        assert_eq!(driver.get_gpio_state(0).unwrap().mode, GpioMode::Disable);
    });
}

// Tests the pin interrupts implementation
#[test]
fn interrupts() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    let gpio_state = Cell::<Option<GpioState>>::new(None);
    let listener = GpioInterruptListener(|gpio, state| {
        assert_eq!(gpio, 0);
        gpio_state.set(Some(state));
    });

    share::scope(|subscribe| {
        assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
        assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
        assert_eq!(gpio_state.get(), Some(GpioState::Low));
    });

    assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
    assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);

    assert!(core::matches!(Gpio::get_pin(11), Err(ErrorCode::Invalid)));
    assert!(core::matches!(Gpio::get_pin(1), Err(ErrorCode::NoDevice)));

    let pin_0 = Gpio::get_pin(0);
    assert!(pin_0.is_ok());

    let _ = pin_0.map(|pin| {
        // Either
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(
                pin.enable_interrupts(crate::PinInterruptEdge::Either),
                Ok(())
            );
            assert_eq!(
                driver.get_gpio_state(0).unwrap().interrupt_enabled,
                Some(InterruptEdge::Either)
            );

            assert_eq!(driver.set_value(0, false), Ok(()));

            let gpio_state = Cell::<Option<GpioState>>::new(None);
            let listener = GpioInterruptListener(|gpio, state| {
                assert_eq!(gpio, 0);
                gpio_state.set(Some(state));
            });

            share::scope(|subscribe| {
                assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::High));
                gpio_state.set(None);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::Low));

                assert_eq!(pin.disable_interrupts(), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
            });
        });

        // Rising
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(
                pin.enable_interrupts(crate::PinInterruptEdge::Rising),
                Ok(())
            );
            assert_eq!(
                driver.get_gpio_state(0).unwrap().interrupt_enabled,
                Some(InterruptEdge::Rising)
            );

            assert_eq!(driver.set_value(0, false), Ok(()));

            let gpio_state = Cell::<Option<GpioState>>::new(None);
            let listener = GpioInterruptListener(|gpio, state| {
                assert_eq!(gpio, 0);
                gpio_state.set(Some(state));
            });

            share::scope(|subscribe| {
                assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::High));
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);

                assert_eq!(pin.disable_interrupts(), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
            });
        });

        // Falling
        let input_pin = pin.make_input::<PullNone>();
        assert!(input_pin.is_ok());
        assert_eq!(
            driver.get_gpio_state(0).unwrap().mode,
            GpioMode::Input(PullMode::PullNone)
        );

        let _ = input_pin.map(|pin| {
            assert_eq!(
                pin.enable_interrupts(crate::PinInterruptEdge::Falling),
                Ok(())
            );
            assert_eq!(
                driver.get_gpio_state(0).unwrap().interrupt_enabled,
                Some(InterruptEdge::Falling)
            );

            assert_eq!(driver.set_value(0, false), Ok(()));

            let gpio_state = Cell::<Option<GpioState>>::new(None);
            let listener = GpioInterruptListener(|gpio, state| {
                assert_eq!(gpio, 0);
                gpio_state.set(Some(state));
            });

            share::scope(|subscribe| {
                assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
                assert_eq!(gpio_state.get(), Some(GpioState::Low));

                assert_eq!(pin.disable_interrupts(), Ok(()));
                assert_eq!(driver.set_value(0, true), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
                assert_eq!(driver.set_value(0, false), Ok(()));
                assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
            });
        });
    });
}

// Tests the pin event subcribe implementation
#[test]
fn subscribe() {
    let kernel = fake::Kernel::new();
    let driver = fake::Gpio::<10>::new();
    driver.set_missing_gpio(1);
    kernel.add_driver(&driver);

    assert_eq!(Gpio::count(), Ok(10));

    let gpio_state = Cell::<Option<GpioState>>::new(None);
    let listener = GpioInterruptListener(|gpio, state| {
        assert_eq!(gpio, 0);
        gpio_state.set(Some(state));
    });

    share::scope(|subscribe| {
        assert_eq!(Gpio::register_listener(&listener, subscribe), Ok(()));
        assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
        assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::Upcall);
        assert_eq!(gpio_state.get(), Some(GpioState::Low));
    });

    assert_eq!(upcall::schedule(DRIVER_NUM, 0, (0, 0, 0)), Ok(()));
    assert_eq!(fake::Syscalls::yield_no_wait(), YieldNoWaitReturn::NoUpcall);
}
<|endoftext|>


<commit_before>use wasm_bindgen::prelude::*;
use linkify::{LinkFinder, LinkKind};

#[wasm_bindgen]
pub fn linkify_text(text: &str, allow_without_scheme: bool) -> String {
    let mut link_finder = LinkFinder::new();
    link_finder.url_must_have_scheme(!allow_without_scheme);
    let mut bytes = Vec::new();
    for span in link_finder.spans(text) {
        match span.kind() {
            Some(LinkKind::Url) => {
                bytes.extend_from_slice(b"");
                escape(span.as_str(), &mut bytes);
                bytes.extend_from_slice(b"");
            }
            Some(LinkKind::Email) => {
                bytes.extend_from_slice(b"");
                escape(span.as_str(), &mut bytes);
                bytes.extend_from_slice(b"");
            }
            _ => {
                escape(span.as_str(), &mut bytes);
            }
        }
    }
    String::from_utf8(bytes).expect("added bytes are all ASCII")
}

fn escape(text: &str, dest: &mut Vec<u8>) {
    for c in text.bytes() {
        match c {
            b'&' => dest.extend_from_slice(b"&"),
            b'<' => dest.extend_from_slice(b"<"),
            b'>' => dest.extend_from_slice(b">"),
            b'"' => dest.extend_from_slice(b"""),
            b'\'' => dest.extend_from_slice(b"'"),
            _ => dest.push(c),
        }
    }
}
<commit_msg>demo: Make it clearer what type the link is, fix links without scheme<commit_after>use wasm_bindgen::prelude::*;
use linkify::{LinkFinder, LinkKind};

#[wasm_bindgen]
pub fn linkify_text(text: &str, allow_without_scheme: bool) -> String {
    let mut link_finder = LinkFinder::new();
    link_finder.url_must_have_scheme(!allow_without_scheme);
    let mut bytes = Vec::new();
    for span in link_finder.spans(text) {
        match span.kind() {
            Some(LinkKind::Url) => {
                let mut url = span.as_str().to_string();
                if !url.contains(":") {
                    url.insert_str(0, "https://");
                }
                bytes.extend_from_slice(b"");
                escape(span.as_str(), &mut bytes);
                bytes.extend_from_slice(b"");
            }
            Some(LinkKind::Email) => {
                bytes.extend_from_slice(b"");
                escape(span.as_str(), &mut bytes);
                bytes.extend_from_slice(b"");
            }
            _ => {
                escape(span.as_str(), &mut bytes);
            }
        }
    }
    String::from_utf8(bytes).expect("added bytes are all ASCII")
}

fn escape(text: &str, dest: &mut Vec<u8>) {
    for c in text.bytes() {
        match c {
            b'&' => dest.extend_from_slice(b"&"),
            b'<' => dest.extend_from_slice(b"<"),
            b'>' => dest.extend_from_slice(b">"),
            b'"' => dest.extend_from_slice(b"""),
            b'\'' => dest.extend_from_slice(b"'"),
            _ => dest.push(c),
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::sym;

use super::BYTES_NTH;

pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) {
    if_chain! {
        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
        let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs();
        let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) {
            Some("String")
        } else if ty.is_str() {
            Some("str")
        } else {
            None
        };
        if let Some(caller_type) = caller_type;
        then {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                BYTES_NTH,
                expr.span,
                &format!("called `.byte().nth()` on a `{}`", caller_type),
                "try calling `.as_bytes().get()`",
                format!(
                    "{}.as_bytes().get({})",
                    snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
                    snippet_with_applicability(cx, args[1].span, "..", &mut applicability)
                ),
                applicability,
            );
        }
    }
}
<commit_msg>Update clippy_lints/src/methods/bytes_nth.rs<commit_after>use crate::utils::{is_type_diagnostic_item, snippet_with_applicability, span_lint_and_sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::sym;

use super::BYTES_NTH;

pub(super) fn lints<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, iter_args: &'tcx [Expr<'tcx>]) {
    if_chain! {
        if let ExprKind::MethodCall(_, _, ref args, _) = expr.kind;
        let ty = cx.typeck_results().expr_ty(&iter_args[0]).peel_refs();
        let caller_type = if is_type_diagnostic_item(cx, ty, sym::string_type) {
            Some("String")
        } else if ty.is_str() {
            Some("str")
        } else {
            None
        };
        if let Some(caller_type) = caller_type;
        then {
            let mut applicability = Applicability::MachineApplicable;
            span_lint_and_sugg(
                cx,
                BYTES_NTH,
                expr.span,
                &format!("called `.byte().nth()` on a `{}`", caller_type),
                "try",
                format!(
                    "{}.as_bytes().get({})",
                    snippet_with_applicability(cx, iter_args[0].span, "..", &mut applicability),
                    snippet_with_applicability(cx, args[1].span, "..", &mut applicability)
                ),
                applicability,
            );
        }
    }
}
<|endoftext|>


<commit_before>use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

#[allow(clippy::module_name_repetitions)]
#[derive(Copy, Clone)]
pub struct UselessVec {
    pub too_large_for_stack: u64,
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for usage of `&vec![..]` when using `&[..]` would
    /// be possible.
    ///
    /// ### Why is this bad?
    /// This is less efficient.
    ///
    /// ### Example
    /// ```rust
    /// # fn foo(my_vec: &[u8]) {}
    ///
    /// // Bad
    /// foo(&vec![1, 2]);
    ///
    /// // Good
    /// foo(&[1, 2]);
    /// ```
    pub USELESS_VEC,
    perf,
    "useless `vec!`"
}

impl_lint_pass!(UselessVec => [USELESS_VEC]);

impl<'tcx> LateLintPass<'tcx> for UselessVec {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
        if_chain! {
            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
            if let ty::Slice(..) = ty.kind();
            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
            if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
            then {
                self.check_vec_macro(cx, &vec_args, mutability, expr.span);
            }
        }

        // search for `for _ in vec![…]`
        if_chain! {
            if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
            if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
            then {
                // report the error around the `vec!` not inside `<std macros>:`
                let span = arg.span
                    .ctxt()
                    .outer_expn_data()
                    .call_site
                    .ctxt()
                    .outer_expn_data()
                    .call_site;
                self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
            }
        }
    }
}

impl UselessVec {
    fn check_vec_macro<'tcx>(
        self,
        cx: &LateContext<'tcx>,
        vec_args: &higher::VecArgs<'tcx>,
        mutability: Mutability,
        span: Span,
    ) {
        let mut applicability = Applicability::MachineApplicable;
        let snippet = match *vec_args {
            higher::VecArgs::Repeat(elem, len) => {
                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
                    #[allow(clippy::cast_possible_truncation)]
                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                        return;
                    }

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!(
                                "&[{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                    }
                } else {
                    return;
                }
            },
            higher::VecArgs::Vec(args) => {
                if let Some(last) = args.iter().last() {
                    #[allow(clippy::cast_possible_truncation)]
                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
                        return;
                    }
                    let span = args[0].span.to(last.span);

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}]",
                                snippet_with_applicability(cx, span, "..", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
                        },
                    }
                } else {
                    match mutability {
                        Mutability::Mut => "&mut []".into(),
                        Mutability::Not => "&[]".into(),
                    }
                }
            },
        };

        span_lint_and_sugg(
            cx,
            USELESS_VEC,
            span,
            "useless use of `vec!`",
            "you can use a slice directly",
            snippet,
            applicability,
        );
    }
}

fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
    let ty = cx.typeck_results().expr_ty_adjusted(expr);
    cx.layout_of(ty).map_or(0, |l| l.size.bytes())
}

/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
fn vec_type(ty: Ty<'_>) -> Ty<'_> {
    if let ty::Adt(_, substs) = ty.kind() {
        substs.type_at(0)
    } else {
        panic!("The type of `vec!` is a not a struct?");
    }
}
<commit_msg>Rollup merge of #89895 - camsteffen:for-loop-head-span, r=davidtwco<commit_after>use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::higher;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::source_map::Span;

#[allow(clippy::module_name_repetitions)]
#[derive(Copy, Clone)]
pub struct UselessVec {
    pub too_large_for_stack: u64,
}

declare_clippy_lint! {
    /// ### What it does
    /// Checks for usage of `&vec![..]` when using `&[..]` would
    /// be possible.
    ///
    /// ### Why is this bad?
    /// This is less efficient.
    ///
    /// ### Example
    /// ```rust
    /// # fn foo(my_vec: &[u8]) {}
    ///
    /// // Bad
    /// foo(&vec![1, 2]);
    ///
    /// // Good
    /// foo(&[1, 2]);
    /// ```
    pub USELESS_VEC,
    perf,
    "useless `vec!`"
}

impl_lint_pass!(UselessVec => [USELESS_VEC]);

impl<'tcx> LateLintPass<'tcx> for UselessVec {
    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        // search for `&vec![_]` expressions where the adjusted type is `&[_]`
        if_chain! {
            if let ty::Ref(_, ty, _) = cx.typeck_results().expr_ty_adjusted(expr).kind();
            if let ty::Slice(..) = ty.kind();
            if let ExprKind::AddrOf(BorrowKind::Ref, mutability, addressee) = expr.kind;
            if let Some(vec_args) = higher::VecArgs::hir(cx, addressee);
            then {
                self.check_vec_macro(cx, &vec_args, mutability, expr.span);
            }
        }

        // search for `for _ in vec![…]`
        if_chain! {
            if let Some(higher::ForLoop { arg, .. }) = higher::ForLoop::hir(expr);
            if let Some(vec_args) = higher::VecArgs::hir(cx, arg);
            if is_copy(cx, vec_type(cx.typeck_results().expr_ty_adjusted(arg)));
            then {
                // report the error around the `vec!` not inside `<std macros>:`
                let span = arg.span.ctxt().outer_expn_data().call_site;
                self.check_vec_macro(cx, &vec_args, Mutability::Not, span);
            }
        }
    }
}

impl UselessVec {
    fn check_vec_macro<'tcx>(
        self,
        cx: &LateContext<'tcx>,
        vec_args: &higher::VecArgs<'tcx>,
        mutability: Mutability,
        span: Span,
    ) {
        let mut applicability = Applicability::MachineApplicable;
        let snippet = match *vec_args {
            higher::VecArgs::Repeat(elem, len) => {
                if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) {
                    #[allow(clippy::cast_possible_truncation)]
                    if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack {
                        return;
                    }

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!(
                                "&[{}; {}]",
                                snippet_with_applicability(cx, elem.span, "elem", &mut applicability),
                                snippet_with_applicability(cx, len.span, "len", &mut applicability)
                            )
                        },
                    }
                } else {
                    return;
                }
            },
            higher::VecArgs::Vec(args) => {
                if let Some(last) = args.iter().last() {
                    #[allow(clippy::cast_possible_truncation)]
                    if args.len() as u64 * size_of(cx, last) > self.too_large_for_stack {
                        return;
                    }
                    let span = args[0].span.to(last.span);

                    match mutability {
                        Mutability::Mut => {
                            format!(
                                "&mut [{}]",
                                snippet_with_applicability(cx, span, "..", &mut applicability)
                            )
                        },
                        Mutability::Not => {
                            format!("&[{}]", snippet_with_applicability(cx, span, "..", &mut applicability))
                        },
                    }
                } else {
                    match mutability {
                        Mutability::Mut => "&mut []".into(),
                        Mutability::Not => "&[]".into(),
                    }
                }
            },
        };

        span_lint_and_sugg(
            cx,
            USELESS_VEC,
            span,
            "useless use of `vec!`",
            "you can use a slice directly",
            snippet,
            applicability,
        );
    }
}

fn size_of(cx: &LateContext<'_>, expr: &Expr<'_>) -> u64 {
    let ty = cx.typeck_results().expr_ty_adjusted(expr);
    cx.layout_of(ty).map_or(0, |l| l.size.bytes())
}

/// Returns the item type of the vector (i.e., the `T` in `Vec<T>`).
fn vec_type(ty: Ty<'_>) -> Ty<'_> {
    if let ty::Adt(_, substs) = ty.kind() {
        substs.type_at(0)
    } else {
        panic!("The type of `vec!` is a not a struct?");
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_config::constants::CORE_CODE_ADDRESS;
use move_core_types::{
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, StructTag},
};
use once_cell::sync::Lazy;

pub const ACCOUNT_MODULE_NAME: &str = "LibraAccount";

// Account
static ACCOUNT_MODULE_IDENTIFIER: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("LibraAccount").unwrap());

/// The ModuleId for the Account module.
pub static ACCOUNT_MODULE: Lazy<ModuleId> =
    Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, ACCOUNT_MODULE_IDENTIFIER.clone()));

// Payment Events
static SENT_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("SentPaymentEvent").unwrap());
static RECEIVED_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("ReceivedPaymentEvent").unwrap());

pub fn sent_event_name() -> &'static IdentStr {
    &*SENT_EVENT_NAME
}

pub fn received_event_name() -> &'static IdentStr {
    &*RECEIVED_EVENT_NAME
}

pub fn sent_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: sent_event_name().to_owned(),
        type_params: vec![],
    }
}

pub fn received_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: received_event_name().to_owned(),
        type_params: vec![],
    }
}
<commit_msg>Removing sent_payment_tag from types/src/account_config/constants/account.rs<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::account_config::constants::CORE_CODE_ADDRESS;
use move_core_types::{
    identifier::{IdentStr, Identifier},
    language_storage::{ModuleId, StructTag},
};
use once_cell::sync::Lazy;

pub const ACCOUNT_MODULE_NAME: &str = "LibraAccount";

// Account
static ACCOUNT_MODULE_IDENTIFIER: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("LibraAccount").unwrap());

/// The ModuleId for the Account module.
pub static ACCOUNT_MODULE: Lazy<ModuleId> =
    Lazy::new(|| ModuleId::new(CORE_CODE_ADDRESS, ACCOUNT_MODULE_IDENTIFIER.clone()));

// Payment Events
static SENT_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("SentPaymentEvent").unwrap());
static RECEIVED_EVENT_NAME: Lazy<Identifier> =
    Lazy::new(|| Identifier::new("ReceivedPaymentEvent").unwrap());

pub fn sent_event_name() -> &'static IdentStr {
    &*SENT_EVENT_NAME
}

pub fn received_event_name() -> &'static IdentStr {
    &*RECEIVED_EVENT_NAME
}

pub fn received_payment_tag() -> StructTag {
    StructTag {
        address: CORE_CODE_ADDRESS,
        module: ACCOUNT_MODULE_IDENTIFIER.clone(),
        name: received_event_name().to_owned(),
        type_params: vec![],
    }
}
<|endoftext|>


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

use dom::baseaudiocontext::{BaseAudioContext, BaseAudioContextOptions};
use dom::bindings::codegen::Bindings::AudioContextBinding;
use dom::bindings::codegen::Bindings::AudioContextBinding::{AudioContextLatencyCategory, AudioContextMethods};
use dom::bindings::codegen::Bindings::AudioContextBinding::{AudioContextOptions, AudioTimestamp};
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState;
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextBinding::BaseAudioContextMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::context::{LatencyCategory, ProcessingState, RealTimeAudioContextOptions};
use std::rc::Rc;
use task_source::TaskSource;

#[dom_struct]
pub struct AudioContext {
    context: BaseAudioContext,
    latency_hint: AudioContextLatencyCategory,
    /// https://webaudio.github.io/web-audio-api/#dom-audiocontext-baselatency
    base_latency: f64,
    /// https://webaudio.github.io/web-audio-api/#dom-audiocontext-outputlatency
    output_latency: f64,
}

impl AudioContext {
    #[allow(unrooted_must_root)]
    // https://webaudio.github.io/web-audio-api/#AudioContext-constructors
    fn new_inherited(options: &AudioContextOptions) -> AudioContext {
        // Steps 1-3.
        let context = BaseAudioContext::new_inherited(
            BaseAudioContextOptions::AudioContext(options.into()),
        );

        // Step 4.1.
        let latency_hint = options.latencyHint;

        // Step 4.2. The sample rate is set during the creation of the BaseAudioContext.
        // servo-media takes care of setting the default sample rate of the output device
        // and of resampling the audio output if needed.

        // Steps 5 and 6 of the construction algorithm will happen in `resume`,
        // after reflecting dom object.

        AudioContext {
            context,
            latency_hint,
            base_latency: 0.,   // TODO
            output_latency: 0., // TODO
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(window: &Window, options: &AudioContextOptions) -> DomRoot<AudioContext> {
        let context = AudioContext::new_inherited(options);
        let context = reflect_dom_object(Box::new(context), window, AudioContextBinding::Wrap);
        context.resume();
        context
    }

    // https://webaudio.github.io/web-audio-api/#AudioContext-constructors
    pub fn Constructor(
        window: &Window,
        options: &AudioContextOptions,
    ) -> Fallible<DomRoot<AudioContext>> {
        Ok(AudioContext::new(window, options))
    }

    fn resume(&self) {
        // Step 5.
        if self.context.is_allowed_to_start() {
            // Step 6.
            self.context.resume();
        }
    }
}

impl AudioContextMethods for AudioContext {
    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-baselatency
    fn BaseLatency(&self) -> Finite<f64> {
        Finite::wrap(self.base_latency)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-outputlatency
    fn OutputLatency(&self) -> Finite<f64> {
        Finite::wrap(self.output_latency)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-outputlatency
    fn GetOutputTimestamp(&self) -> AudioTimestamp {
        // TODO
        AudioTimestamp {
            contextTime: Some(Finite::wrap(0.)),
            performanceTime: Some(Finite::wrap(0.)),
        }
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspend
    #[allow(unrooted_must_root)]
    fn Suspend(&self) -> Rc<Promise> {
        // Step 1.
        let promise = Promise::new(&self.global());

        // Step 2.
        if self.context.control_thread_state() == ProcessingState::Closed {
            promise.reject_error(Error::InvalidState);
            return promise;
        }

        // Step 3.
        if self.context.State() == AudioContextState::Suspended {
            promise.resolve_native(&());
            return promise;
        }

        // Steps 4 and 5.
        let window = DomRoot::downcast::<Window>(self.global()).unwrap();
        let task_source = window.dom_manipulation_task_source();
        let trusted_promise = TrustedPromise::new(promise.clone());
        match self.context.audio_context_impl().suspend() {
            Ok(_) => {
                let base_context = Trusted::new(&self.context);
                let context = Trusted::new(self);
                let _ = task_source.queue(
                    task!(suspend_ok: move || {
                    let base_context = base_context.root();
                    let context = context.root();
                    let promise = trusted_promise.root();
                    promise.resolve_native(&());
                    if base_context.State() != AudioContextState::Suspended {
                        base_context.set_state_attribute(AudioContextState::Suspended);
                        let window = DomRoot::downcast::<Window>(context.global()).unwrap();
                        window.dom_manipulation_task_source().queue_simple_event(
                            context.upcast(),
                            atom!("statechange"),
                            &window
                            );
                    }
                }),
                    window.upcast(),
                );
            },
            Err(_) => {
                // The spec does not define the error case and `suspend` should
                // never fail, but we handle the case here for completion.
                let _ = task_source.queue(
                    task!(suspend_error: move || {
                    let promise = trusted_promise.root();
                    promise.reject_error(Error::Type("Something went wrong".to_owned()));
                }),
                    window.upcast(),
                );
            },
        };

        // Step 6.
        promise
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-close
    #[allow(unrooted_must_root)]
    fn Close(&self) -> Rc<Promise> {
        // Step 1.
        let promise = Promise::new(&self.global());

        // Step 2.
        if self.context.control_thread_state() == ProcessingState::Closed {
            promise.reject_error(Error::InvalidState);
            return promise;
        }

        // Step 3.
        if self.context.State() == AudioContextState::Closed {
            promise.resolve_native(&());
            return promise;
        }

        // Steps 4 and 5.
        let window = DomRoot::downcast::<Window>(self.global()).unwrap();
        let task_source = window.dom_manipulation_task_source();
        let trusted_promise = TrustedPromise::new(promise.clone());
        match self.context.audio_context_impl().close() {
            Ok(_) => {
                let base_context = Trusted::new(&self.context);
                let context = Trusted::new(self);
                let _ = task_source.queue(
                    task!(suspend_ok: move || {
                    let base_context = base_context.root();
                    let context = context.root();
                    let promise = trusted_promise.root();
                    promise.resolve_native(&());
                    if base_context.State() != AudioContextState::Closed {
                        base_context.set_state_attribute(AudioContextState::Closed);
                        let window = DomRoot::downcast::<Window>(context.global()).unwrap();
                        window.dom_manipulation_task_source().queue_simple_event(
                            context.upcast(),
                            atom!("statechange"),
                            &window
                            );
                    }
                }),
                    window.upcast(),
                );
            },
            Err(_) => {
                // The spec does not define the error case and `suspend` should
                // never fail, but we handle the case here for completion.
                let _ = task_source.queue(
                    task!(suspend_error: move || {
                    let promise = trusted_promise.root();
                    promise.reject_error(Error::Type("Something went wrong".to_owned()));
                }),
                    window.upcast(),
                );
            },
        };

        // Step 6.
        promise
    }
}

impl From<AudioContextLatencyCategory> for LatencyCategory {
    fn from(category: AudioContextLatencyCategory) -> Self {
        match category {
            AudioContextLatencyCategory::Balanced => LatencyCategory::Balanced,
            AudioContextLatencyCategory::Interactive => LatencyCategory::Interactive,
            AudioContextLatencyCategory::Playback => LatencyCategory::Playback,
        }
    }
}

impl<'a> From<&'a AudioContextOptions> for RealTimeAudioContextOptions {
    fn from(options: &AudioContextOptions) -> Self {
        Self {
            sample_rate: *options.sampleRate.unwrap_or(Finite::wrap(48000.)),
            latency_hint: options.latencyHint.into(),
        }
    }
}
<commit_msg>48000 -> 44100<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::baseaudiocontext::{BaseAudioContext, BaseAudioContextOptions};
use dom::bindings::codegen::Bindings::AudioContextBinding;
use dom::bindings::codegen::Bindings::AudioContextBinding::{AudioContextLatencyCategory, AudioContextMethods};
use dom::bindings::codegen::Bindings::AudioContextBinding::{AudioContextOptions, AudioTimestamp};
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::AudioContextState;
use dom::bindings::codegen::Bindings::BaseAudioContextBinding::BaseAudioContextBinding::BaseAudioContextMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::inheritance::Castable;
use dom::bindings::num::Finite;
use dom::bindings::refcounted::{Trusted, TrustedPromise};
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::root::DomRoot;
use dom::promise::Promise;
use dom::window::Window;
use dom_struct::dom_struct;
use servo_media::audio::context::{LatencyCategory, ProcessingState, RealTimeAudioContextOptions};
use std::rc::Rc;
use task_source::TaskSource;

#[dom_struct]
pub struct AudioContext {
    context: BaseAudioContext,
    latency_hint: AudioContextLatencyCategory,
    /// https://webaudio.github.io/web-audio-api/#dom-audiocontext-baselatency
    base_latency: f64,
    /// https://webaudio.github.io/web-audio-api/#dom-audiocontext-outputlatency
    output_latency: f64,
}

impl AudioContext {
    #[allow(unrooted_must_root)]
    // https://webaudio.github.io/web-audio-api/#AudioContext-constructors
    fn new_inherited(options: &AudioContextOptions) -> AudioContext {
        // Steps 1-3.
        let context = BaseAudioContext::new_inherited(
            BaseAudioContextOptions::AudioContext(options.into()),
        );

        // Step 4.1.
        let latency_hint = options.latencyHint;

        // Step 4.2. The sample rate is set during the creation of the BaseAudioContext.
        // servo-media takes care of setting the default sample rate of the output device
        // and of resampling the audio output if needed.

        // Steps 5 and 6 of the construction algorithm will happen in `resume`,
        // after reflecting dom object.

        AudioContext {
            context,
            latency_hint,
            base_latency: 0.,   // TODO
            output_latency: 0., // TODO
        }
    }

    #[allow(unrooted_must_root)]
    pub fn new(window: &Window, options: &AudioContextOptions) -> DomRoot<AudioContext> {
        let context = AudioContext::new_inherited(options);
        let context = reflect_dom_object(Box::new(context), window, AudioContextBinding::Wrap);
        context.resume();
        context
    }

    // https://webaudio.github.io/web-audio-api/#AudioContext-constructors
    pub fn Constructor(
        window: &Window,
        options: &AudioContextOptions,
    ) -> Fallible<DomRoot<AudioContext>> {
        Ok(AudioContext::new(window, options))
    }

    fn resume(&self) {
        // Step 5.
        if self.context.is_allowed_to_start() {
            // Step 6.
            self.context.resume();
        }
    }
}

impl AudioContextMethods for AudioContext {
    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-baselatency
    fn BaseLatency(&self) -> Finite<f64> {
        Finite::wrap(self.base_latency)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-outputlatency
    fn OutputLatency(&self) -> Finite<f64> {
        Finite::wrap(self.output_latency)
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-outputlatency
    fn GetOutputTimestamp(&self) -> AudioTimestamp {
        // TODO
        AudioTimestamp {
            contextTime: Some(Finite::wrap(0.)),
            performanceTime: Some(Finite::wrap(0.)),
        }
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-suspend
    #[allow(unrooted_must_root)]
    fn Suspend(&self) -> Rc<Promise> {
        // Step 1.
        let promise = Promise::new(&self.global());

        // Step 2.
        if self.context.control_thread_state() == ProcessingState::Closed {
            promise.reject_error(Error::InvalidState);
            return promise;
        }

        // Step 3.
        if self.context.State() == AudioContextState::Suspended {
            promise.resolve_native(&());
            return promise;
        }

        // Steps 4 and 5.
        let window = DomRoot::downcast::<Window>(self.global()).unwrap();
        let task_source = window.dom_manipulation_task_source();
        let trusted_promise = TrustedPromise::new(promise.clone());
        match self.context.audio_context_impl().suspend() {
            Ok(_) => {
                let base_context = Trusted::new(&self.context);
                let context = Trusted::new(self);
                let _ = task_source.queue(
                    task!(suspend_ok: move || {
                    let base_context = base_context.root();
                    let context = context.root();
                    let promise = trusted_promise.root();
                    promise.resolve_native(&());
                    if base_context.State() != AudioContextState::Suspended {
                        base_context.set_state_attribute(AudioContextState::Suspended);
                        let window = DomRoot::downcast::<Window>(context.global()).unwrap();
                        window.dom_manipulation_task_source().queue_simple_event(
                            context.upcast(),
                            atom!("statechange"),
                            &window
                            );
                    }
                }),
                    window.upcast(),
                );
            },
            Err(_) => {
                // The spec does not define the error case and `suspend` should
                // never fail, but we handle the case here for completion.
                let _ = task_source.queue(
                    task!(suspend_error: move || {
                    let promise = trusted_promise.root();
                    promise.reject_error(Error::Type("Something went wrong".to_owned()));
                }),
                    window.upcast(),
                );
            },
        };

        // Step 6.
        promise
    }

    // https://webaudio.github.io/web-audio-api/#dom-audiocontext-close
    #[allow(unrooted_must_root)]
    fn Close(&self) -> Rc<Promise> {
        // Step 1.
        let promise = Promise::new(&self.global());

        // Step 2.
        if self.context.control_thread_state() == ProcessingState::Closed {
            promise.reject_error(Error::InvalidState);
            return promise;
        }

        // Step 3.
        if self.context.State() == AudioContextState::Closed {
            promise.resolve_native(&());
            return promise;
        }

        // Steps 4 and 5.
        let window = DomRoot::downcast::<Window>(self.global()).unwrap();
        let task_source = window.dom_manipulation_task_source();
        let trusted_promise = TrustedPromise::new(promise.clone());
        match self.context.audio_context_impl().close() {
            Ok(_) => {
                let base_context = Trusted::new(&self.context);
                let context = Trusted::new(self);
                let _ = task_source.queue(
                    task!(suspend_ok: move || {
                    let base_context = base_context.root();
                    let context = context.root();
                    let promise = trusted_promise.root();
                    promise.resolve_native(&());
                    if base_context.State() != AudioContextState::Closed {
                        base_context.set_state_attribute(AudioContextState::Closed);
                        let window = DomRoot::downcast::<Window>(context.global()).unwrap();
                        window.dom_manipulation_task_source().queue_simple_event(
                            context.upcast(),
                            atom!("statechange"),
                            &window
                            );
                    }
                }),
                    window.upcast(),
                );
            },
            Err(_) => {
                // The spec does not define the error case and `suspend` should
                // never fail, but we handle the case here for completion.
                let _ = task_source.queue(
                    task!(suspend_error: move || {
                    let promise = trusted_promise.root();
                    promise.reject_error(Error::Type("Something went wrong".to_owned()));
                }),
                    window.upcast(),
                );
            },
        };

        // Step 6.
        promise
    }
}

impl From<AudioContextLatencyCategory> for LatencyCategory {
    fn from(category: AudioContextLatencyCategory) -> Self {
        match category {
            AudioContextLatencyCategory::Balanced => LatencyCategory::Balanced,
            AudioContextLatencyCategory::Interactive => LatencyCategory::Interactive,
            AudioContextLatencyCategory::Playback => LatencyCategory::Playback,
        }
    }
}

impl<'a> From<&'a AudioContextOptions> for RealTimeAudioContextOptions {
    fn from(options: &AudioContextOptions) -> Self {
        Self {
            sample_rate: *options.sampleRate.unwrap_or(Finite::wrap(44100.)),
            latency_hint: options.latencyHint.into(),
        }
    }
}
<|endoftext|>


<commit_before>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::ptr;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

#[cfg(not(test))]
pub fn init() {}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
        c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
        _ => {}
    }

    match errno {
        c::WSAEACCES => ErrorKind::PermissionDenied,
        c::WSAEADDRINUSE => ErrorKind::AddrInUse,
        c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        c::WSAECONNABORTED => ErrorKind::ConnectionAborted,
        c::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
        c::WSAECONNRESET => ErrorKind::ConnectionReset,
        c::WSAEINVAL => ErrorKind::InvalidInput,
        c::WSAENOTCONN => ErrorKind::NotConnected,
        c::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
        c::WSAETIMEDOUT => ErrorKind::TimedOut,

        _ => ErrorKind::Other,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while start.len() >= 8 {
        macro_rules! if_return {
            ($($n:literal,)+) => {
                $(
                    if start[$n] == needle {
                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
                    }
                )+
            }
        }

        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);

        start = &start[8..];
    }

    for (i, c) in start.iter().enumerate() {
        if *c == needle {
            return Some((start.as_ptr() as usize - ptr as usize) / 2 + i);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new(
                ErrorKind::InvalidInput,
                "strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
fn wide_char_to_multi_byte(
    code_page: u32,
    flags: u32,
    s: &[u16],
    no_default_char: bool,
) -> crate::io::Result<Vec<i8>> {
    unsafe {
        let mut size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            ptr::null_mut(),
            0,
            ptr::null(),
            ptr::null_mut(),
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }

        let mut buf = Vec::with_capacity(size as usize);
        buf.set_len(size as usize);

        let mut used_default_char = c::FALSE;
        size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            buf.as_mut_ptr(),
            buf.len() as i32,
            ptr::null(),
            if no_default_char { &mut used_default_char } else { ptr::null_mut() },
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }
        if no_default_char && used_default_char == c::TRUE {
            return Err(crate::io::Error::new(
                crate::io::ErrorKind::InvalidData,
                "string cannot be converted to requested code page",
            ));
        }

        buf.set_len(size as usize);

        Ok(buf)
    }
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

// On Windows, use the processor-specific __fastfail mechanism.  In Windows 8
// and later, this will terminate the process immediately without running any
// in-process exception handlers.  In earlier versions of Windows, this
// sequence of instructions will be treated as an access violation,
// terminating the process but without necessarily bypassing all exception
// handlers.
//
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    unsafe {
        llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
        crate::intrinsics::unreachable();
    }
    crate::intrinsics::abort();
}
<commit_msg>Get pointer from address of c directly<commit_after>#![allow(missing_docs, nonstandard_style)]

use crate::ffi::{OsStr, OsString};
use crate::io::ErrorKind;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::path::PathBuf;
use crate::ptr;
use crate::time::Duration;

pub use self::rand::hashmap_random_keys;
pub use libc::strlen;

#[macro_use]
pub mod compat;

pub mod alloc;
pub mod args;
pub mod c;
pub mod cmath;
pub mod condvar;
pub mod env;
pub mod ext;
pub mod fs;
pub mod handle;
pub mod io;
pub mod memchr;
pub mod mutex;
pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
pub mod pipe;
pub mod process;
pub mod rand;
pub mod rwlock;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;
cfg_if::cfg_if! {
    if #[cfg(not(target_vendor = "uwp"))] {
        pub mod stdio;
        pub mod stack_overflow;
    } else {
        pub mod stdio_uwp;
        pub mod stack_overflow_uwp;
        pub use self::stdio_uwp as stdio;
        pub use self::stack_overflow_uwp as stack_overflow;
    }
}

#[cfg(not(test))]
pub fn init() {}

pub fn decode_error_kind(errno: i32) -> ErrorKind {
    match errno as c::DWORD {
        c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied,
        c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists,
        c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe,
        c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound,
        c::ERROR_NO_DATA => return ErrorKind::BrokenPipe,
        c::ERROR_INVALID_PARAMETER => return ErrorKind::InvalidInput,
        c::ERROR_SEM_TIMEOUT
        | c::WAIT_TIMEOUT
        | c::ERROR_DRIVER_CANCEL_TIMEOUT
        | c::ERROR_OPERATION_ABORTED
        | c::ERROR_SERVICE_REQUEST_TIMEOUT
        | c::ERROR_COUNTER_TIMEOUT
        | c::ERROR_TIMEOUT
        | c::ERROR_RESOURCE_CALL_TIMED_OUT
        | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT
        | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT
        | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT
        | c::ERROR_DS_TIMELIMIT_EXCEEDED
        | c::DNS_ERROR_RECORD_TIMED_OUT
        | c::ERROR_IPSEC_IKE_TIMED_OUT
        | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT
        | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut,
        _ => {}
    }

    match errno {
        c::WSAEACCES => ErrorKind::PermissionDenied,
        c::WSAEADDRINUSE => ErrorKind::AddrInUse,
        c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
        c::WSAECONNABORTED => ErrorKind::ConnectionAborted,
        c::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
        c::WSAECONNRESET => ErrorKind::ConnectionReset,
        c::WSAEINVAL => ErrorKind::InvalidInput,
        c::WSAENOTCONN => ErrorKind::NotConnected,
        c::WSAEWOULDBLOCK => ErrorKind::WouldBlock,
        c::WSAETIMEDOUT => ErrorKind::TimedOut,

        _ => ErrorKind::Other,
    }
}

pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
    let ptr = haystack.as_ptr();
    let mut start = &haystack[..];

    // For performance reasons unfold the loop eight times.
    while start.len() >= 8 {
        macro_rules! if_return {
            ($($n:literal,)+) => {
                $(
                    if start[$n] == needle {
                        return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
                    }
                )+
            }
        }

        if_return!(0, 1, 2, 3, 4, 5, 6, 7,);

        start = &start[8..];
    }

    for c in start {
        if *c == needle {
            return Some((c as *const u16 as usize - ptr as usize) / 2);
        }
    }
    None
}

pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> {
    fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> {
        let mut maybe_result: Vec<u16> = s.encode_wide().collect();
        if unrolled_find_u16s(0, &maybe_result).is_some() {
            return Err(crate::io::Error::new(
                ErrorKind::InvalidInput,
                "strings passed to WinAPI cannot contain NULs",
            ));
        }
        maybe_result.push(0);
        Ok(maybe_result)
    }
    inner(s.as_ref())
}

// Many Windows APIs follow a pattern of where we hand a buffer and then they
// will report back to us how large the buffer should be or how many bytes
// currently reside in the buffer. This function is an abstraction over these
// functions by making them easier to call.
//
// The first callback, `f1`, is yielded a (pointer, len) pair which can be
// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
// The closure is expected to return what the syscall returns which will be
// interpreted by this function to determine if the syscall needs to be invoked
// again (with more buffer space).
//
// Once the syscall has completed (errors bail out early) the second closure is
// yielded the data which has been read from the syscall. The return value
// from this closure is then the return value of the function.
fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> crate::io::Result<T>
where
    F1: FnMut(*mut u16, c::DWORD) -> c::DWORD,
    F2: FnOnce(&[u16]) -> T,
{
    // Start off with a stack buf but then spill over to the heap if we end up
    // needing more space.
    let mut stack_buf = [0u16; 512];
    let mut heap_buf = Vec::new();
    unsafe {
        let mut n = stack_buf.len();
        loop {
            let buf = if n <= stack_buf.len() {
                &mut stack_buf[..]
            } else {
                let extra = n - heap_buf.len();
                heap_buf.reserve(extra);
                heap_buf.set_len(n);
                &mut heap_buf[..]
            };

            // This function is typically called on windows API functions which
            // will return the correct length of the string, but these functions
            // also return the `0` on error. In some cases, however, the
            // returned "correct length" may actually be 0!
            //
            // To handle this case we call `SetLastError` to reset it to 0 and
            // then check it again if we get the "0 error value". If the "last
            // error" is still 0 then we interpret it as a 0 length buffer and
            // not an actual error.
            c::SetLastError(0);
            let k = match f1(buf.as_mut_ptr(), n as c::DWORD) {
                0 if c::GetLastError() == 0 => 0,
                0 => return Err(crate::io::Error::last_os_error()),
                n => n,
            } as usize;
            if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER {
                n *= 2;
            } else if k >= n {
                n = k;
            } else {
                return Ok(f2(&buf[..k]));
            }
        }
    }
}

fn os2path(s: &[u16]) -> PathBuf {
    PathBuf::from(OsString::from_wide(s))
}

#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename()
fn wide_char_to_multi_byte(
    code_page: u32,
    flags: u32,
    s: &[u16],
    no_default_char: bool,
) -> crate::io::Result<Vec<i8>> {
    unsafe {
        let mut size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            ptr::null_mut(),
            0,
            ptr::null(),
            ptr::null_mut(),
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }

        let mut buf = Vec::with_capacity(size as usize);
        buf.set_len(size as usize);

        let mut used_default_char = c::FALSE;
        size = c::WideCharToMultiByte(
            code_page,
            flags,
            s.as_ptr(),
            s.len() as i32,
            buf.as_mut_ptr(),
            buf.len() as i32,
            ptr::null(),
            if no_default_char { &mut used_default_char } else { ptr::null_mut() },
        );
        if size == 0 {
            return Err(crate::io::Error::last_os_error());
        }
        if no_default_char && used_default_char == c::TRUE {
            return Err(crate::io::Error::new(
                crate::io::ErrorKind::InvalidData,
                "string cannot be converted to requested code page",
            ));
        }

        buf.set_len(size as usize);

        Ok(buf)
    }
}

pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] {
    match unrolled_find_u16s(0, v) {
        // don't include the 0
        Some(i) => &v[..i],
        None => v,
    }
}

pub trait IsZero {
    fn is_zero(&self) -> bool;
}

macro_rules! impl_is_zero {
    ($($t:ident)*) => ($(impl IsZero for $t {
        fn is_zero(&self) -> bool {
            *self == 0
        }
    })*)
}

impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

pub fn cvt<I: IsZero>(i: I) -> crate::io::Result<I> {
    if i.is_zero() { Err(crate::io::Error::last_os_error()) } else { Ok(i) }
}

pub fn dur2timeout(dur: Duration) -> c::DWORD {
    // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the
    // timeouts in windows APIs are typically u32 milliseconds. To translate, we
    // have two pieces to take care of:
    //
    // * Nanosecond precision is rounded up
    // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE
    //   (never time out).
    dur.as_secs()
        .checked_mul(1000)
        .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000))
        .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 }))
        .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD })
        .unwrap_or(c::INFINITE)
}

// On Windows, use the processor-specific __fastfail mechanism.  In Windows 8
// and later, this will terminate the process immediately without running any
// in-process exception handlers.  In earlier versions of Windows, this
// sequence of instructions will be treated as an access violation,
// terminating the process but without necessarily bypassing all exception
// handlers.
//
// https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail
#[allow(unreachable_code)]
pub fn abort_internal() -> ! {
    #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
    unsafe {
        llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
        crate::intrinsics::unreachable();
    }
    crate::intrinsics::abort();
}
<|endoftext|>