<commit_before>#[macro_use]
extern crate serde_derive;
extern crate chan_signal;
extern crate docopt;
extern crate rand;
extern crate sled;

use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

use chan_signal::Signal;
use docopt::Docopt;
use rand::{thread_rng, Rng};

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --kv-len=<l>       The length of both keys and values [default: 2].
";

#[derive(Deserialize)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_kv_len: usize,
}

fn report(shutdown: Arc<AtomicBool>, total: Arc<AtomicUsize>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = total.load(Ordering::Acquire);

        println!("did {} ops", total - last);

        last = total;
    }
}

fn run(
    tree: Arc<sled::Tree>,
    shutdown: Arc<AtomicBool>,
    total: Arc<AtomicUsize>,
    kv_len: usize,
) {
    let byte = || {
        thread_rng()
            .gen_iter::<u8>()
            .take(kv_len)
            .collect::<Vec<_>>()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        total.fetch_add(1, Ordering::Release);
        let choice = rng.gen_range(0, 5);

        match choice {
            0 => {
                tree.set(byte(), byte()).unwrap();
            }
            1 => {
                tree.get(&*byte()).unwrap();
            }
            2 => {
                tree.del(&*byte()).unwrap();
            }
            3 => match tree.cas(byte(), Some(byte()), Some(byte())) {
                Ok(_) | Err(sled::Error::CasFailed(_)) => {}
                other => panic!("operational error: {:?}", other),
            },
            4 => {
                let _ = tree
                    .scan(&*byte())
                    .take(rng.gen_range(0, 15))
                    .map(|res| res.unwrap())
                    .collect::<Vec<_>>();
            }
            _ => panic!("impossible choice"),
        }
    }
}

fn main() {
    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| {
            d.argv(std::env::args().into_iter()).deserialize()
        }).unwrap_or_else(|e| e.exit());

    let total = Arc::new(AtomicUsize::new(0));
    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::ConfigBuilder::new()
        .io_bufs(2)
        .io_buf_size(8_000_000)
        .blink_fanout(32)
        .page_consolidation_threshold(10)
        .cache_bits(6)
        .cache_capacity(1_000_000)
        .flush_every_ms(Some(100))
        .snapshot_after_ops(1000000)
        .print_profile_on_drop(true)
        .build();

    let tree = Arc::new(sled::Tree::start(config).unwrap());

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;
    let kv_len = args.flag_kv_len;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();
        let total = total.clone();

        let t = if i == 0 {
            thread::spawn(move || report(shutdown, total))
        } else {
            thread::spawn(move || run(tree, shutdown, total, kv_len))
        };

        threads.push(t);
    }

    if args.flag_burn_in {
        println!("waiting on signal");
        signal.recv();
        println!("got shutdown signal, cleaning up...");
    } else {
        thread::sleep(std::time::Duration::from_secs(
            args.flag_duration,
        ));
    }

    shutdown.store(true, Ordering::SeqCst);

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = total.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}
<commit_msg>Fix `USAGE` string in stress2<commit_after>#[macro_use]
extern crate serde_derive;
extern crate chan_signal;
extern crate docopt;
extern crate rand;
extern crate sled;

use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;

use chan_signal::Signal;
use docopt::Docopt;
use rand::{thread_rng, Rng};

const USAGE: &'static str = "
Usage: stress [--threads=<#>] [--burn-in] [--duration=<s>] [--kv-len=<l>]

Options:
    --threads=<#>      Number of threads [default: 4].
    --burn-in          Don't halt until we receive a signal.
    --duration=<s>     Seconds to run for [default: 10].
    --kv-len=<l>       The length of both keys and values [default: 2].
";

#[derive(Deserialize)]
struct Args {
    flag_threads: usize,
    flag_burn_in: bool,
    flag_duration: u64,
    flag_kv_len: usize,
}

fn report(shutdown: Arc<AtomicBool>, total: Arc<AtomicUsize>) {
    let mut last = 0;
    while !shutdown.load(Ordering::Relaxed) {
        thread::sleep(std::time::Duration::from_secs(1));
        let total = total.load(Ordering::Acquire);

        println!("did {} ops", total - last);

        last = total;
    }
}

fn run(
    tree: Arc<sled::Tree>,
    shutdown: Arc<AtomicBool>,
    total: Arc<AtomicUsize>,
    kv_len: usize,
) {
    let byte = || {
        thread_rng()
            .gen_iter::<u8>()
            .take(kv_len)
            .collect::<Vec<_>>()
    };
    let mut rng = thread_rng();

    while !shutdown.load(Ordering::Relaxed) {
        total.fetch_add(1, Ordering::Release);
        let choice = rng.gen_range(0, 5);

        match choice {
            0 => {
                tree.set(byte(), byte()).unwrap();
            }
            1 => {
                tree.get(&*byte()).unwrap();
            }
            2 => {
                tree.del(&*byte()).unwrap();
            }
            3 => match tree.cas(byte(), Some(byte()), Some(byte())) {
                Ok(_) | Err(sled::Error::CasFailed(_)) => {}
                other => panic!("operational error: {:?}", other),
            },
            4 => {
                let _ = tree
                    .scan(&*byte())
                    .take(rng.gen_range(0, 15))
                    .map(|res| res.unwrap())
                    .collect::<Vec<_>>();
            }
            _ => panic!("impossible choice"),
        }
    }
}

fn main() {
    let signal = chan_signal::notify(&[Signal::INT, Signal::TERM]);

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| {
            d.argv(std::env::args().into_iter()).deserialize()
        }).unwrap_or_else(|e| e.exit());

    let total = Arc::new(AtomicUsize::new(0));
    let shutdown = Arc::new(AtomicBool::new(false));

    let config = sled::ConfigBuilder::new()
        .io_bufs(2)
        .io_buf_size(8_000_000)
        .blink_fanout(32)
        .page_consolidation_threshold(10)
        .cache_bits(6)
        .cache_capacity(1_000_000)
        .flush_every_ms(Some(100))
        .snapshot_after_ops(1000000)
        .print_profile_on_drop(true)
        .build();

    let tree = Arc::new(sled::Tree::start(config).unwrap());

    let mut threads = vec![];

    let now = std::time::Instant::now();

    let n_threads = args.flag_threads;
    let kv_len = args.flag_kv_len;

    for i in 0..n_threads + 1 {
        let tree = tree.clone();
        let shutdown = shutdown.clone();
        let total = total.clone();

        let t = if i == 0 {
            thread::spawn(move || report(shutdown, total))
        } else {
            thread::spawn(move || run(tree, shutdown, total, kv_len))
        };

        threads.push(t);
    }

    if args.flag_burn_in {
        println!("waiting on signal");
        signal.recv();
        println!("got shutdown signal, cleaning up...");
    } else {
        thread::sleep(std::time::Duration::from_secs(
            args.flag_duration,
        ));
    }

    shutdown.store(true, Ordering::SeqCst);

    for t in threads.into_iter() {
        t.join().unwrap();
    }

    let ops = total.load(Ordering::SeqCst);
    let time = now.elapsed().as_secs() as usize;

    println!(
        "did {} total ops in {} seconds. {} ops/s",
        ops,
        time,
        (ops * 1_000) / (time * 1_000)
    );
}
<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;

fn main() {
    let out_path = env::current_dir().unwrap();
    // For native targets, include all types and functions
    bindgen::Builder::default()
        .header(
            out_path
                .join("../spirv_cross/src/wrapper.hpp")
                .to_str()
                .unwrap(),
        )
        .clang_arg("-I/Library/Developer/CommandLineTools/usr/include/c++/v1")
        .clang_arg("-I/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/include")
        .clang_args(["-x", "c++", "-std=c++14"].iter())
        .enable_cxx_namespaces()
        .whitelist_function("sc_internal.*")
        .whitelist_type("spv::.*")
        .whitelist_type("Sc.*")
        .bitfield_enum(".*(Mask|Flags)")
        .rustified_enum("spv::BuiltIn")
        .rustified_enum("spv::Decoration")
        .rustified_enum("spv::ExecutionModel")
        .rustified_enum("ScInternalResult")
        .rustified_enum("spirv_cross::SPIRType_BaseType")
        .rustified_enum("spirv_cross::MSLVertexFormat")
        .opaque_type("std::.*")
        .clang_args(vec![
            "-DSPIRV_CROSS_WRAPPER_GLSL",
            "-DSPIRV_CROSS_WRAPPER_MSL",
            "-DSPIRV_CROSS_WRAPPER_HLSL",
        ])
        .layout_tests(false)
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(out_path.join("../spirv_cross/src/bindings_native.rs"))
        .expect("Couldn't write bindings!");
    // For wasm targets, include all types, functions will be implemented manually
    bindgen::Builder::default()
        .header(
            out_path
                .join("../spirv_cross/src/wrapper.hpp")
                .to_str()
                .unwrap(),
        )
        .clang_arg("-I/Library/Developer/CommandLineTools/usr/include/c++/v1")
        .clang_arg("-I/Library/Developer/CommandLineTools/usr/lib/clang/10.0.1/include")
        .clang_args(["-x", "c++", "-std=c++14"].iter())
        .enable_cxx_namespaces()
        .whitelist_type("spv::.*")
        .whitelist_type("Sc.*")
        .bitfield_enum(".*(Mask|Flags)")
        .rustified_enum("spv::BuiltIn")
        .rustified_enum("spv::Decoration")
        .rustified_enum("spv::ExecutionModel")
        .rustified_enum("ScInternalResult")
        .rustified_enum("spirv_cross::SPIRType_BaseType")
        .rustified_enum("spirv_cross::MSLVertexFormat")
        .opaque_type("std::.*")
        .clang_args(vec![
            "-DSPIRV_CROSS_WRAPPER_GLSL",
            "-DSPIRV_CROSS_WRAPPER_MSL",
            "-DSPIRV_CROSS_WRAPPER_HLSL",
        ])
        .layout_tests(false)
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(out_path.join("../spirv_cross/src/bindings_wasm.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>Remove temporary clang workaround<commit_after>extern crate bindgen;

use std::env;

fn main() {
    let out_path = env::current_dir().unwrap();
    // For native targets, include all types and functions
    bindgen::Builder::default()
        .header(
            out_path
                .join("../spirv_cross/src/wrapper.hpp")
                .to_str()
                .unwrap(),
        )
        .clang_args(["-x", "c++", "-std=c++14"].iter())
        .enable_cxx_namespaces()
        .whitelist_function("sc_internal.*")
        .whitelist_type("spv::.*")
        .whitelist_type("Sc.*")
        .bitfield_enum(".*(Mask|Flags)")
        .rustified_enum("spv::BuiltIn")
        .rustified_enum("spv::Decoration")
        .rustified_enum("spv::ExecutionModel")
        .rustified_enum("ScInternalResult")
        .rustified_enum("spirv_cross::SPIRType_BaseType")
        .rustified_enum("spirv_cross::MSLVertexFormat")
        .opaque_type("std::.*")
        .clang_args(vec![
            "-DSPIRV_CROSS_WRAPPER_GLSL",
            "-DSPIRV_CROSS_WRAPPER_MSL",
            "-DSPIRV_CROSS_WRAPPER_HLSL",
        ])
        .layout_tests(false)
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(out_path.join("../spirv_cross/src/bindings_native.rs"))
        .expect("Couldn't write bindings!");
    // For wasm targets, include all types, functions will be implemented manually
    bindgen::Builder::default()
        .header(
            out_path
                .join("../spirv_cross/src/wrapper.hpp")
                .to_str()
                .unwrap(),
        )
        .clang_args(["-x", "c++", "-std=c++14"].iter())
        .enable_cxx_namespaces()
        .whitelist_type("spv::.*")
        .whitelist_type("Sc.*")
        .bitfield_enum(".*(Mask|Flags)")
        .rustified_enum("spv::BuiltIn")
        .rustified_enum("spv::Decoration")
        .rustified_enum("spv::ExecutionModel")
        .rustified_enum("ScInternalResult")
        .rustified_enum("spirv_cross::SPIRType_BaseType")
        .rustified_enum("spirv_cross::MSLVertexFormat")
        .opaque_type("std::.*")
        .clang_args(vec![
            "-DSPIRV_CROSS_WRAPPER_GLSL",
            "-DSPIRV_CROSS_WRAPPER_MSL",
            "-DSPIRV_CROSS_WRAPPER_HLSL",
        ])
        .layout_tests(false)
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(out_path.join("../spirv_cross/src/bindings_wasm.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>use color::{Color, PuyoColor, RealColor};
use field;

pub struct PlainField<C: Color<C> + Copy + PartialEq<C>> {
    field: [[C; field::MAP_HEIGHT]; field::MAP_WIDTH],
}

impl<C: Color<C> + Copy + PartialEq<C>> PlainField<C> {
    pub fn new() -> PlainField<C> {
        let w = C::wall_color();
        let e = C::empty_color();
        PlainField {
            field: [
                //        4           8          12          16
                [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
            ]
        }
    }

    pub fn from_str(s: &str) -> PlainField<C> {
        let mut field = Self::new();

        assert!(s.len() % 6 == 0);

        let mut cnt = 0;
        for b in s.bytes().rev() {
            let x = 6 - (cnt % 6);
            let y = (cnt / 6) + 1;
            field.set_color(x, y, C::from_byte(b));
            cnt += 1;
        }

        field
    }

    pub fn color(&self, x: i32, y: i32) -> C {
        // self.field[x as usize][y as usize]

        debug_assert!(0 <= x && x < 8);
        debug_assert!(0 <= y && y < 16);
        unsafe {
            *self.field.get_unchecked(x as usize).get_unchecked(y as usize)
        }
    }

    pub fn set_color(&mut self, x: i32, y: i32, color: C) {
        // self.field[x as usize][y as usize] = color

        debug_assert!(0 <= x && x < 8);
        debug_assert!(0 <= y && y < 16);
        unsafe {
            *self.field.get_unchecked_mut(x as usize).get_unchecked_mut(y as usize) = color
        }
    }

    pub fn is_empty(&self, x: i32, y: i32) -> bool {
        self.color(x, y) == C::empty_color()
    }

    pub fn is_color(&self, x: i32, y: i32, color: C) -> bool {
        self.color(x, y) == color
    }

    pub fn drop(&mut self) {
        for x in 1 .. 7 {
            let mut h = 1;
            for y in 1 .. 14 {
                if self.is_empty(x, y) {
                    continue;
                }
                let c = self.color(x, y);
                self.set_color(x, h, c);
                h += 1;
            }

            while h <= 13 {
                self.set_color(x, h, C::empty_color());
                h += 1;
            }
        }
    }
}

impl<C> PartialEq<PlainField<C>> for PlainField<C>
where C: Color<C> + Copy + PartialEq<C> {
    fn eq(&self, other: &PlainField<C>) -> bool {
        // TODO(mayah): Would be good memory comparison.
        for x in 0..8 {
            for y in 0..16 {
                if self.color(x, y) != other.color(x, y) {
                    return false
                }
            }
        }

        true
    }
}

pub type PuyoPlainField = PlainField<PuyoColor>;
pub type RealPlainField = PlainField<RealColor>;

#[cfg(test)]
mod tests {
    use std::mem;
    use color::PuyoColor;
    use plain_field::PuyoPlainField;

    #[test]
    fn test_memory_size() {
        assert_eq!(mem::size_of::<PuyoPlainField>(), 128);
    }

    #[test]
    fn test_color() {
        let pf = PuyoPlainField::from_str("RGYB@&");
        assert_eq!(pf.color(0, 1), PuyoColor::WALL);
        assert_eq!(pf.color(1, 1), PuyoColor::RED);
        assert_eq!(pf.color(2, 1), PuyoColor::GREEN);
        assert_eq!(pf.color(3, 1), PuyoColor::YELLOW);
        assert_eq!(pf.color(4, 1), PuyoColor::BLUE);
        assert_eq!(pf.color(5, 1), PuyoColor::OJAMA);
        assert_eq!(pf.color(6, 1), PuyoColor::IRON);
        assert_eq!(pf.color(7, 1), PuyoColor::WALL);

        assert_eq!(pf.color(1, 2), PuyoColor::EMPTY);
    }

    #[test]
    fn test_is_color() {
        let pf = PuyoPlainField::from_str("RGYB@&");
        assert!(pf.is_color(0, 1, PuyoColor::WALL));
        assert!(pf.is_color(1, 1, PuyoColor::RED));
        assert!(pf.is_color(2, 1, PuyoColor::GREEN));
        assert!(pf.is_color(3, 1, PuyoColor::YELLOW));
        assert!(pf.is_color(4, 1, PuyoColor::BLUE));
        assert!(pf.is_color(5, 1, PuyoColor::OJAMA));
        assert!(pf.is_color(6, 1, PuyoColor::IRON));
        assert!(pf.is_color(7, 1, PuyoColor::WALL));

        assert!(pf.is_color(1, 2, PuyoColor::EMPTY));
    }

    #[test]
    fn test_is_empty() {
        let pf = PuyoPlainField::from_str("RGYB@&");
        assert!(pf.is_empty(1, 2));
        assert!(!pf.is_empty(1, 1));
    }

    #[test]
    fn test_drop() {
        let mut pf = PuyoPlainField::from_str(concat!(
            "RRRBBB",
            "......",
            "RRRBBB",
            "......",
            "RRRBBB"));
        let expected = PuyoPlainField::from_str(concat!(
            "RRRBBB",
            "RRRBBB",
            "RRRBBB"));

        pf.drop();
        assert!(pf == expected);
    }

    #[test]
    fn test_drop_extreme() {
        let mut pf = PuyoPlainField::from_str(concat!(
            "OOOOOO", // 14
            "OOOOOO", // 13
            "......", // 12
            "......",
            "......",
            "......",
            "......", // 8
            "......",
            "......",
            "......",
            "......", // 4
            "......",
            "......",
            "......"));

        let expected = PuyoPlainField::from_str(concat!(
            "OOOOOO", // 14
            "......", // 13
            "......", // 12
            "......",
            "......",
            "......",
            "......", // 8
            "......",
            "......",
            "......",
            "......", // 4
            "......",
            "......",
            "OOOOOO"));

        pf.drop();
        assert!(pf == expected);
    }
}
<commit_msg>Use usize instead of i32 for indexing.<commit_after>use color::{Color, PuyoColor, RealColor};
use field;

pub struct PlainField<C: Color<C> + Copy + PartialEq<C>> {
    field: [[C; field::MAP_HEIGHT]; field::MAP_WIDTH],
}

impl<C: Color<C> + Copy + PartialEq<C>> PlainField<C> {
    pub fn new() -> PlainField<C> {
        let w = C::wall_color();
        let e = C::empty_color();
        PlainField {
            field: [
                //        4           8          12          16
                [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, e, e, e, e, e, e, e, e, e, e, e, e, e, e, w],
                [w, w, w, w, w, w, w, w, w, w, w, w, w, w, w, w],
            ]
        }
    }

    pub fn from_str(s: &str) -> PlainField<C> {
        let mut field = Self::new();

        assert!(s.len() % 6 == 0);

        let mut cnt = 0;
        for b in s.bytes().rev() {
            let x = 6 - (cnt % 6);
            let y = (cnt / 6) + 1;
            field.set_color(x, y, C::from_byte(b));
            cnt += 1;
        }

        field
    }

    pub fn color(&self, x: usize, y: usize) -> C {
        // self.field[x as usize][y as usize]

        debug_assert!(x < 8);
        debug_assert!(y < 16);
        unsafe {
            *self.field.get_unchecked(x).get_unchecked(y)
        }
    }

    pub fn set_color(&mut self, x: usize, y: usize, color: C) {
        // self.field[x as usize][y as usize] = color

        debug_assert!(x < 8);
        debug_assert!(y < 16);
        unsafe {
            *self.field.get_unchecked_mut(x).get_unchecked_mut(y) = color
        }
    }

    pub fn is_empty(&self, x: usize, y: usize) -> bool {
        self.color(x, y) == C::empty_color()
    }

    pub fn is_color(&self, x: usize, y: usize, color: C) -> bool {
        self.color(x, y) == color
    }

    pub fn drop(&mut self) {
        for x in 1 .. 7 {
            let mut h = 1;
            for y in 1 .. 14 {
                if self.is_empty(x, y) {
                    continue;
                }
                let c = self.color(x, y);
                self.set_color(x, h, c);
                h += 1;
            }

            while h <= 13 {
                self.set_color(x, h, C::empty_color());
                h += 1;
            }
        }
    }
}

impl<C> PartialEq<PlainField<C>> for PlainField<C>
where C: Color<C> + Copy + PartialEq<C> {
    fn eq(&self, other: &PlainField<C>) -> bool {
        // TODO(mayah): Would be good memory comparison.
        for x in 0..8 {
            for y in 0..16 {
                if self.color(x, y) != other.color(x, y) {
                    return false
                }
            }
        }

        true
    }
}

pub type PuyoPlainField = PlainField<PuyoColor>;
pub type RealPlainField = PlainField<RealColor>;

#[cfg(test)]
mod tests {
    use std::mem;
    use color::PuyoColor;
    use plain_field::PuyoPlainField;

    #[test]
    fn test_memory_size() {
        assert_eq!(mem::size_of::<PuyoPlainField>(), 128);
    }

    #[test]
    fn test_color() {
        let pf = PuyoPlainField::from_str("RGYB@&");
        assert_eq!(pf.color(0, 1), PuyoColor::WALL);
        assert_eq!(pf.color(1, 1), PuyoColor::RED);
        assert_eq!(pf.color(2, 1), PuyoColor::GREEN);
        assert_eq!(pf.color(3, 1), PuyoColor::YELLOW);
        assert_eq!(pf.color(4, 1), PuyoColor::BLUE);
        assert_eq!(pf.color(5, 1), PuyoColor::OJAMA);
        assert_eq!(pf.color(6, 1), PuyoColor::IRON);
        assert_eq!(pf.color(7, 1), PuyoColor::WALL);

        assert_eq!(pf.color(1, 2), PuyoColor::EMPTY);
    }

    #[test]
    fn test_is_color() {
        let pf = PuyoPlainField::from_str("RGYB@&");
        assert!(pf.is_color(0, 1, PuyoColor::WALL));
        assert!(pf.is_color(1, 1, PuyoColor::RED));
        assert!(pf.is_color(2, 1, PuyoColor::GREEN));
        assert!(pf.is_color(3, 1, PuyoColor::YELLOW));
        assert!(pf.is_color(4, 1, PuyoColor::BLUE));
        assert!(pf.is_color(5, 1, PuyoColor::OJAMA));
        assert!(pf.is_color(6, 1, PuyoColor::IRON));
        assert!(pf.is_color(7, 1, PuyoColor::WALL));

        assert!(pf.is_color(1, 2, PuyoColor::EMPTY));
    }

    #[test]
    fn test_is_empty() {
        let pf = PuyoPlainField::from_str("RGYB@&");
        assert!(pf.is_empty(1, 2));
        assert!(!pf.is_empty(1, 1));
    }

    #[test]
    fn test_drop() {
        let mut pf = PuyoPlainField::from_str(concat!(
            "RRRBBB",
            "......",
            "RRRBBB",
            "......",
            "RRRBBB"));
        let expected = PuyoPlainField::from_str(concat!(
            "RRRBBB",
            "RRRBBB",
            "RRRBBB"));

        pf.drop();
        assert!(pf == expected);
    }

    #[test]
    fn test_drop_extreme() {
        let mut pf = PuyoPlainField::from_str(concat!(
            "OOOOOO", // 14
            "OOOOOO", // 13
            "......", // 12
            "......",
            "......",
            "......",
            "......", // 8
            "......",
            "......",
            "......",
            "......", // 4
            "......",
            "......",
            "......"));

        let expected = PuyoPlainField::from_str(concat!(
            "OOOOOO", // 14
            "......", // 13
            "......", // 12
            "......",
            "......",
            "......",
            "......", // 8
            "......",
            "......",
            "......",
            "......", // 4
            "......",
            "......",
            "OOOOOO"));

        pf.drop();
        assert!(pf == expected);
    }
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use {
  crate::{
    grammar::{Element, ElementTypes, Grammar, Prod, ProdKey},
    utils::{TreeNode, TreeValue, Void},
  },
  anyhow::Error,
  derivative::Derivative,
  std::collections::{BTreeMap, BTreeSet},
};

#[derive(Derivative)]
#[derivative(
  Clone(bound = ""),
  PartialEq(bound = ""),
  Eq(bound = ""),
  PartialOrd(bound = ""),
  Ord(bound = ""),
  Debug(bound = ""),
  PartialOrd = "feature_allow_slow_enum",
  Ord = "feature_allow_slow_enum"
)]
struct InternalNullableInfo<'a, E: ElementTypes> {
  /// The set of productions that are nullable
  nullable_actions: BTreeSet<Prod<'a, E>>,
}

impl<E: ElementTypes> InternalNullableInfo<'_, E> {
  pub fn new() -> Self {
    InternalNullableInfo {
      nullable_actions: BTreeSet::new(),
    }
  }
}

/// Calculate the nullable set of a grammar
///
/// The nullable set of a grammar is the set of non-terminals in that grammar
/// that can parse the empty terminal sequence.
fn inner_calculate_nullables<E: ElementTypes>(
  g: &Grammar<E>,
) -> BTreeMap<E::NonTerm, InternalNullableInfo<E>> {
  let prods = g.prods().collect::<Vec<_>>();

  let mut nullable_nts: BTreeMap<E::NonTerm, InternalNullableInfo<E>> =
    BTreeMap::new();

  loop {
    let mut changed = false;

    for prod in &prods {
      if is_prod_nullable(&nullable_nts, prod) {
        let nullable_info = nullable_nts
          .entry(prod.head().clone())
          .or_insert_with(InternalNullableInfo::new);
        if nullable_info.nullable_actions.insert(*prod) {
          changed = true;
        }
      }
    }

    if !changed {
      return nullable_nts;
    }
  }
}

#[derive(Derivative)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
pub struct GrammarNullableInfo<E: ElementTypes> {
  nonterm_info: BTreeMap<E::NonTerm, NonTermNullableInfo<E>>,
}

impl<E: ElementTypes> GrammarNullableInfo<E> {
  pub fn nonterm_info(&self) -> &BTreeMap<E::NonTerm, NonTermNullableInfo<E>> {
    &self.nonterm_info
  }

  pub fn is_nullable(&self, nt: &E::NonTerm) -> bool {
    self.nonterm_info.contains_key(nt)
  }

  pub fn is_prod_nullable(&self, prod: &Prod<E>) -> bool {
    is_prod_nullable(&self.nonterm_info, prod)
  }

  pub fn get_nullable_info(
    &self,
    nt: &E::NonTerm,
  ) -> Option<&NonTermNullableInfo<E>> {
    self.nonterm_info.get(nt)
  }

  pub fn get_nullable_set(&self) -> BTreeSet<E::NonTerm> {
    self.nonterm_info().keys().cloned().collect()
  }
}

#[derive(Derivative)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
pub struct NonTermNullableInfo<E: ElementTypes> {
  nullable_action: TreeNode<ProdKey<E>, Void>,
}

impl<E: ElementTypes> NonTermNullableInfo<E> {
  pub fn nullable_action(&self) -> &TreeNode<ProdKey<E>, Void> {
    &self.nullable_action
  }
}

#[derive(Debug, thiserror::Error)]
pub enum NullableError {
  #[error("found nullable ambiguities in grammar")]
  NullableAmbiguity,
}

pub fn calculate_nullables<E: ElementTypes>(
  g: &Grammar<E>,
) -> Result<GrammarNullableInfo<E>, Error> {
  let inner_info = inner_calculate_nullables(g);

  // Sanity check outputs.
  for (_, info) in &inner_info {
    let actions_length = info.nullable_actions.len();
    if actions_length == 0 {
      panic!("Unexpectedly empty nullable action!")
    } else if actions_length > 1 {
      return Err(NullableError::NullableAmbiguity.into());
    }
  }

  // Calculate simple nullable map, mapping one nullable nonterminal to one
  // production action
  let mut nullable_action_map = BTreeMap::new();
  for (nt, info) in &inner_info {
    nullable_action_map.insert(nt, get_only(&info.nullable_actions));
  }

  let mut remaining_nullables: BTreeSet<E::NonTerm> =
    inner_info.keys().cloned().collect();
  let mut nullable_infos: BTreeMap<E::NonTerm, NonTermNullableInfo<E>> =
    BTreeMap::new();
  loop {
    'outer: for null_nt in &remaining_nullables {
      let prod = nullable_action_map.get(&null_nt).unwrap();

      let mut nullable_tree_fields: BTreeMap<_, TreeValue<_, Void>> =
        BTreeMap::new();
      for prod_elem in prod.prod_elements() {
        if let (Some(id), Element::NonTerm(nt)) =
          (prod_elem.id(), prod_elem.elem())
        {
          match nullable_infos.get(nt) {
            None => continue 'outer,
            Some(s) => nullable_tree_fields.insert(
              id.clone(),
              TreeValue::Node(Box::new(s.nullable_action.clone())),
            ),
          };
        }
      }

      nullable_infos.insert(
        null_nt.clone(),
        NonTermNullableInfo {
          nullable_action: TreeNode::new(prod.prod_key(), nullable_tree_fields),
        },
      );
    }

    nullable_infos.keys().for_each(|nt| {
      remaining_nullables.remove(nt);
    });

    if remaining_nullables.len() == 0 {
      break;
    }
  }

  Ok(GrammarNullableInfo {
    nonterm_info: nullable_infos,
  })
}

fn is_prod_nullable<E: ElementTypes, V>(
  nullables: &BTreeMap<E::NonTerm, V>,
  prod: &Prod<E>,
) -> bool {
  for elem in prod.elements_iter() {
    match elem {
      Element::Term(_) => return false,
      Element::NonTerm(nt) => {
        if !nullables.contains_key(nt) {
          return false;
        }
      }
    }
  }
  true
}

// Helpers

fn get_only<I: IntoIterator>(op: I) -> I::Item {
  let mut iter = op.into_iter();
  let value = iter.next().expect("get_only argument must not be empty.");
  assert!(
    iter.next().is_none(),
    "get_only argument must not have more than one value."
  );
  value
}

#[cfg(test)]
mod test {
  use super::*;
  use crate::grammar::examples;
  use crate::grammar::NonTerminal;

  #[test]
  fn test_simple_grammar() {
    let g = examples::make_simple();
    let nullables = calculate_nullables(&g).unwrap();
    assert!(nullables.get_nullable_set().is_empty());
  }

  #[test]
  fn test_simple_nullable_grammar() {
    let g = examples::make_simple_nullable();
    let nullables = calculate_nullables(&g).unwrap();
    let nullable_set = nullables.get_nullable_set();
    assert!(nullable_set.contains(&NonTerminal::new("start")));
    assert!(nullable_set.contains(&NonTerminal::new("a")));
    assert!(nullable_set.contains(&NonTerminal::new("b")));
    assert!(nullable_set.contains(&NonTerminal::new("c")));
  }

  #[test]
  fn test_paren_grammar() {
    let g = examples::make_paren();
    let nullables = calculate_nullables(&g).unwrap();
    assert!(nullables
      .get_nullable_info(&NonTerminal::new("expr_list"))
      .is_some());
    assert!(nullables
      .get_nullable_info(&NonTerminal::new("expr"))
      .is_none());
    assert!(nullables
      .get_nullable_info(&NonTerminal::new("start"))
      .is_none());
  }

  #[test]
  fn test_ambiguous_nullable_grammar() {
    let g = examples::make_ambiguous_nullable();
    let nullable_error = calculate_nullables(&g).unwrap_err();
    assert!(nullable_error.downcast_ref::<NullableError>().is_some());
  }
}
<commit_msg>Remove remaining derivatives::Derivatives<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use {
  crate::{
    grammar::{Element, ElementTypes, Grammar, Prod, ProdKey},
    utils::{TreeNode, TreeValue, Void},
  },
  anyhow::Error,
  std::collections::{BTreeMap, BTreeSet},
};

#[derive(Derivative)]
#[derivative(
  Clone(bound = ""),
  PartialEq(bound = ""),
  Eq(bound = ""),
  PartialOrd(bound = ""),
  Ord(bound = ""),
  Debug(bound = ""),
)]
struct InternalNullableInfo<'a, E: ElementTypes> {
  /// The set of productions that are nullable
  nullable_actions: BTreeSet<Prod<'a, E>>,
}

impl<E: ElementTypes> InternalNullableInfo<'_, E> {
  pub fn new() -> Self {
    InternalNullableInfo {
      nullable_actions: BTreeSet::new(),
    }
  }
}

/// Calculate the nullable set of a grammar
///
/// The nullable set of a grammar is the set of non-terminals in that grammar
/// that can parse the empty terminal sequence.
fn inner_calculate_nullables<E: ElementTypes>(
  g: &Grammar<E>,
) -> BTreeMap<E::NonTerm, InternalNullableInfo<E>> {
  let prods = g.prods().collect::<Vec<_>>();

  let mut nullable_nts: BTreeMap<E::NonTerm, InternalNullableInfo<E>> =
    BTreeMap::new();

  loop {
    let mut changed = false;

    for prod in &prods {
      if is_prod_nullable(&nullable_nts, prod) {
        let nullable_info = nullable_nts
          .entry(prod.head().clone())
          .or_insert_with(InternalNullableInfo::new);
        if nullable_info.nullable_actions.insert(*prod) {
          changed = true;
        }
      }
    }

    if !changed {
      return nullable_nts;
    }
  }
}

#[derive(Derivative)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
pub struct GrammarNullableInfo<E: ElementTypes> {
  nonterm_info: BTreeMap<E::NonTerm, NonTermNullableInfo<E>>,
}

impl<E: ElementTypes> GrammarNullableInfo<E> {
  pub fn nonterm_info(&self) -> &BTreeMap<E::NonTerm, NonTermNullableInfo<E>> {
    &self.nonterm_info
  }

  pub fn is_nullable(&self, nt: &E::NonTerm) -> bool {
    self.nonterm_info.contains_key(nt)
  }

  pub fn is_prod_nullable(&self, prod: &Prod<E>) -> bool {
    is_prod_nullable(&self.nonterm_info, prod)
  }

  pub fn get_nullable_info(
    &self,
    nt: &E::NonTerm,
  ) -> Option<&NonTermNullableInfo<E>> {
    self.nonterm_info.get(nt)
  }

  pub fn get_nullable_set(&self) -> BTreeSet<E::NonTerm> {
    self.nonterm_info().keys().cloned().collect()
  }
}

#[derive(Derivative)]
#[derivative(Clone(bound = ""), Debug(bound = ""))]
pub struct NonTermNullableInfo<E: ElementTypes> {
  nullable_action: TreeNode<ProdKey<E>, Void>,
}

impl<E: ElementTypes> NonTermNullableInfo<E> {
  pub fn nullable_action(&self) -> &TreeNode<ProdKey<E>, Void> {
    &self.nullable_action
  }
}

#[derive(Debug, thiserror::Error)]
pub enum NullableError {
  #[error("found nullable ambiguities in grammar")]
  NullableAmbiguity,
}

pub fn calculate_nullables<E: ElementTypes>(
  g: &Grammar<E>,
) -> Result<GrammarNullableInfo<E>, Error> {
  let inner_info = inner_calculate_nullables(g);

  // Sanity check outputs.
  for (_, info) in &inner_info {
    let actions_length = info.nullable_actions.len();
    if actions_length == 0 {
      panic!("Unexpectedly empty nullable action!")
    } else if actions_length > 1 {
      return Err(NullableError::NullableAmbiguity.into());
    }
  }

  // Calculate simple nullable map, mapping one nullable nonterminal to one
  // production action
  let mut nullable_action_map = BTreeMap::new();
  for (nt, info) in &inner_info {
    nullable_action_map.insert(nt, get_only(&info.nullable_actions));
  }

  let mut remaining_nullables: BTreeSet<E::NonTerm> =
    inner_info.keys().cloned().collect();
  let mut nullable_infos: BTreeMap<E::NonTerm, NonTermNullableInfo<E>> =
    BTreeMap::new();
  loop {
    'outer: for null_nt in &remaining_nullables {
      let prod = nullable_action_map.get(&null_nt).unwrap();

      let mut nullable_tree_fields: BTreeMap<_, TreeValue<_, Void>> =
        BTreeMap::new();
      for prod_elem in prod.prod_elements() {
        if let (Some(id), Element::NonTerm(nt)) =
          (prod_elem.id(), prod_elem.elem())
        {
          match nullable_infos.get(nt) {
            None => continue 'outer,
            Some(s) => nullable_tree_fields.insert(
              id.clone(),
              TreeValue::Node(Box::new(s.nullable_action.clone())),
            ),
          };
        }
      }

      nullable_infos.insert(
        null_nt.clone(),
        NonTermNullableInfo {
          nullable_action: TreeNode::new(prod.prod_key(), nullable_tree_fields),
        },
      );
    }

    nullable_infos.keys().for_each(|nt| {
      remaining_nullables.remove(nt);
    });

    if remaining_nullables.len() == 0 {
      break;
    }
  }

  Ok(GrammarNullableInfo {
    nonterm_info: nullable_infos,
  })
}

fn is_prod_nullable<E: ElementTypes, V>(
  nullables: &BTreeMap<E::NonTerm, V>,
  prod: &Prod<E>,
) -> bool {
  for elem in prod.elements_iter() {
    match elem {
      Element::Term(_) => return false,
      Element::NonTerm(nt) => {
        if !nullables.contains_key(nt) {
          return false;
        }
      }
    }
  }
  true
}

// Helpers

fn get_only<I: IntoIterator>(op: I) -> I::Item {
  let mut iter = op.into_iter();
  let value = iter.next().expect("get_only argument must not be empty.");
  assert!(
    iter.next().is_none(),
    "get_only argument must not have more than one value."
  );
  value
}

#[cfg(test)]
mod test {
  use super::*;
  use crate::grammar::examples;
  use crate::grammar::NonTerminal;

  #[test]
  fn test_simple_grammar() {
    let g = examples::make_simple();
    let nullables = calculate_nullables(&g).unwrap();
    assert!(nullables.get_nullable_set().is_empty());
  }

  #[test]
  fn test_simple_nullable_grammar() {
    let g = examples::make_simple_nullable();
    let nullables = calculate_nullables(&g).unwrap();
    let nullable_set = nullables.get_nullable_set();
    assert!(nullable_set.contains(&NonTerminal::new("start")));
    assert!(nullable_set.contains(&NonTerminal::new("a")));
    assert!(nullable_set.contains(&NonTerminal::new("b")));
    assert!(nullable_set.contains(&NonTerminal::new("c")));
  }

  #[test]
  fn test_paren_grammar() {
    let g = examples::make_paren();
    let nullables = calculate_nullables(&g).unwrap();
    assert!(nullables
      .get_nullable_info(&NonTerminal::new("expr_list"))
      .is_some());
    assert!(nullables
      .get_nullable_info(&NonTerminal::new("expr"))
      .is_none());
    assert!(nullables
      .get_nullable_info(&NonTerminal::new("start"))
      .is_none());
  }

  #[test]
  fn test_ambiguous_nullable_grammar() {
    let g = examples::make_ambiguous_nullable();
    let nullable_error = calculate_nullables(&g).unwrap_err();
    assert!(nullable_error.downcast_ref::<NullableError>().is_some());
  }
}
<|endoftext|>


<commit_before><commit_msg>うるう年のやつ<commit_after><|endoftext|>


<commit_before>
pub use self::rc::Rc;

mod rc;

#[lang = "owned_box"]
pub struct Box<T>(*mut T);

impl<T: ::core::fmt::Show> ::core::fmt::Show for Box<T>
{
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(),::core::fmt::FormatError>
	{
		(**self).fmt(f)
	}
}

// vim: ft=rust

<commit_msg>Kernel/Box - Use 'where' for parameter bound<commit_after>
pub use self::rc::Rc;

mod rc;

#[lang = "owned_box"]
pub struct Box<T>(*mut T);

impl<T> ::core::fmt::Show for Box<T>
where
	T: ::core::fmt::Show
{
	fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::result::Result<(),::core::fmt::FormatError>
	{
		(**self).fmt(f)
	}
}

// vim: ft=rust

<|endoftext|>


<commit_before>extern mod std;
priv use std::time::{ precise_time_ns };

priv use common::problem::{ Problem };

#[path="./common/mod.rs"]
mod common;

#[path="./prob0001_0050/mod.rs"]
mod prob0001_0050;
#[path="./prob0051_0100/mod.rs"]
mod prob0051_0100;

priv static problem_sets: &'static [&'static [&'static Problem<'static>]] = &[
    prob0001_0050::problems,
    prob0051_0100::problems
];

priv fn each_problems(f: &fn(&Problem) -> bool) {
    for problem_sets.each_val |ps| {
        for ps.each_val |p| {
            if !f(p) { return; }
        }
    }
}

priv static NSEC_PER_SEC: u64 = 1000000000;
priv fn nanosec_to_str(nsec: u64) -> ~str {
    return fmt!("%3u.%09u",
         (nsec / NSEC_PER_SEC) as uint,
         (nsec % NSEC_PER_SEC) as uint);
}

priv fn solve(p: &Problem) -> u64 {
    let start_time = precise_time_ns();
    let comp_answer = (p.solver)();
    let calc_time   = precise_time_ns() - start_time;

    io::println(fmt!("%-5u %-12s %s",
                     p.id, p.answer, nanosec_to_str(calc_time)));

    assert_eq!(comp_answer, p.answer.to_str());

    return calc_time;
}

fn main() {
    let nums = os::args().filter_mapped(|&s| uint::from_str(s));

    let mut total_time = 0;
    let mut solve_cnt = 0;
    if nums.is_empty() {
        for each_problems |p| {
            total_time += solve(p);
            solve_cnt += 1;
        }
    } else {
        for nums.each_val |n| {
            for each_problems |p| {
                if p.id == n {
                    total_time += solve(p);
                    solve_cnt += 1;
                }
            }
        }
    }

    if solve_cnt > 1 {
        io::println(fmt!("TOTAL %-12s %s", "", nanosec_to_str(total_time)));
    }
}
<commit_msg>Minor fix of output format<commit_after>extern mod std;
priv use std::time::{ precise_time_ns };

priv use common::problem::{ Problem };

#[path="./common/mod.rs"]
mod common;

#[path="./prob0001_0050/mod.rs"]
mod prob0001_0050;
#[path="./prob0051_0100/mod.rs"]
mod prob0051_0100;

priv static problem_sets: &'static [&'static [&'static Problem<'static>]] = &[
    prob0001_0050::problems,
    prob0051_0100::problems
];

priv fn each_problems(f: &fn(&Problem) -> bool) {
    for problem_sets.each_val |ps| {
        for ps.each_val |p| {
            if !f(p) { return; }
        }
    }
}

priv static NSEC_PER_SEC: u64 = 1000000000;
priv fn nanosec_to_str(nsec: u64) -> ~str {
    return fmt!("%3u.%09u",
         (nsec / NSEC_PER_SEC) as uint,
         (nsec % NSEC_PER_SEC) as uint);
}

priv fn solve(p: &Problem) -> u64 {
    let start_time = precise_time_ns();
    let comp_answer = (p.solver)();
    let calc_time   = precise_time_ns() - start_time;

    io::println(fmt!("%-5u %-20s %s",
                     p.id, comp_answer, nanosec_to_str(calc_time)));

    assert_eq!(comp_answer, p.answer.to_str());

    return calc_time;
}

fn main() {
    let nums = os::args().filter_mapped(|&s| uint::from_str(s));

    let mut total_time = 0;
    let mut solve_cnt = 0;
    if nums.is_empty() {
        for each_problems |p| {
            total_time += solve(p);
            solve_cnt += 1;
        }
    } else {
        for nums.each_val |n| {
            for each_problems |p| {
                if p.id == n {
                    total_time += solve(p);
                    solve_cnt += 1;
                }
            }
        }
    }

    if solve_cnt > 1 {
        io::println(fmt!("TOTAL %-12s %s", "", nanosec_to_str(total_time)));
    }
}
<|endoftext|>


<commit_before>//! Crate `ruma_events_macros` provides a procedural macro for generating
//! [ruma-events](https://github.com/ruma/ruma-events) events.
//!
//! See the documentation for the `ruma_event!` macro for usage details.
#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
    warnings
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
// Since we support Rust 1.36.0, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "128"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::{gen::RumaEvent, parse::RumaEventInput};

mod gen;
mod parse;

// A note about the `example` modules that appears in doctests:
//
// This is necessary because otherwise the expanded code appears in function context, which makes
// the compiler interpret the output of the macro as a statement, and proc macros currently aren't
// allowed to expand to statements, resulting in a compiler error.

/// Generates a Rust type for a Matrix event.
///
/// # Examples
///
/// The most common form of event is a struct with all the standard fields for an event of its
/// kind and a struct for its `content` field:
///
/// ```ignore
/// # pub mod example {
/// # use ruma_events_macros::ruma_event;
/// ruma_event! {
///     /// Informs the room about what room aliases it has been given.
///     AliasesEvent {
///         kind: StateEvent,
///         event_type: RoomAliases,
///         content: {
///             /// A list of room aliases.
///             pub aliases: Vec<ruma_identifiers::RoomAliasId>,
///         }
///     }
/// }
/// # }
/// ```
///
/// Occasionally an event will have non-standard fields at its top level (outside the `content`
/// field). These extra fields are declared in block labeled with `fields`:
///
/// ```ignore
/// # pub mod example {
/// # use ruma_events_macros::ruma_event;
/// ruma_event! {
///     /// A redaction of an event.
///     RedactionEvent {
///         kind: RoomEvent,
///         event_type: RoomRedaction,
///         fields: {
///             /// The ID of the event that was redacted.
///             pub redacts: ruma_identifiers::EventId
///         },
///         content: {
///             /// The reason for the redaction, if any.
///             pub reason: Option<String>,
///         },
///     }
/// }
/// # }
/// ```
///
/// Sometimes the type of the `content` should be a type alias rather than a struct or enum. This
/// is designated with `content_type_alias`:
///
/// ```ignore
/// # pub mod example {
/// # use ruma_events_macros::ruma_event;
/// ruma_event! {
///     /// Informs the client about the rooms that are considered direct by a user.
///     DirectEvent {
///         kind: Event,
///         event_type: Direct,
///         content_type_alias: {
///             /// The payload of a `DirectEvent`.
///             ///
///             /// A mapping of `UserId`'s to a collection of `RoomId`'s which are considered
///             /// *direct* for that particular user.
///             std::collections::HashMap<ruma_identifiers::UserId, Vec<ruma_identifiers::RoomId>>
///         }
///     }
/// }
/// # }
/// ```
///
/// If `content` and `content_type_alias` are both supplied, the second one listed will overwrite
/// the first.
///
/// The event type and content type will have copies generated inside a private `raw` module. These
/// "raw" versions are the same, except they implement `serde::Deserialize`. An implementation of
/// `FromRaw` will be provided, which will allow the user to deserialize the event type as
/// `EventResult<EventType>`.
#[proc_macro]
pub fn ruma_event(input: TokenStream) -> TokenStream {
    let ruma_event_input = syn::parse_macro_input!(input as RumaEventInput);

    let ruma_event = RumaEvent::from(ruma_event_input);

    ruma_event.into_token_stream().into()
}
<commit_msg>Don't deny(warnings)<commit_after>//! Crate `ruma_events_macros` provides a procedural macro for generating
//! [ruma-events](https://github.com/ruma/ruma-events) events.
//!
//! See the documentation for the `ruma_event!` macro for usage details.
#![deny(
    missing_copy_implementations,
    missing_debug_implementations,
    // missing_docs, # Uncomment when https://github.com/rust-lang/rust/pull/60562 is released.
)]
#![warn(
    clippy::empty_line_after_outer_attr,
    clippy::expl_impl_clone_on_copy,
    clippy::if_not_else,
    clippy::items_after_statements,
    clippy::match_same_arms,
    clippy::mem_forget,
    clippy::missing_docs_in_private_items,
    clippy::multiple_inherent_impl,
    clippy::mut_mut,
    clippy::needless_borrow,
    clippy::needless_continue,
    clippy::single_match_else,
    clippy::unicode_not_nfc,
    clippy::use_self,
    clippy::used_underscore_binding,
    clippy::wrong_pub_self_convention,
    clippy::wrong_self_convention
)]
// Since we support Rust 1.36.0, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "128"]

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::{gen::RumaEvent, parse::RumaEventInput};

mod gen;
mod parse;

// A note about the `example` modules that appears in doctests:
//
// This is necessary because otherwise the expanded code appears in function context, which makes
// the compiler interpret the output of the macro as a statement, and proc macros currently aren't
// allowed to expand to statements, resulting in a compiler error.

/// Generates a Rust type for a Matrix event.
///
/// # Examples
///
/// The most common form of event is a struct with all the standard fields for an event of its
/// kind and a struct for its `content` field:
///
/// ```ignore
/// # pub mod example {
/// # use ruma_events_macros::ruma_event;
/// ruma_event! {
///     /// Informs the room about what room aliases it has been given.
///     AliasesEvent {
///         kind: StateEvent,
///         event_type: RoomAliases,
///         content: {
///             /// A list of room aliases.
///             pub aliases: Vec<ruma_identifiers::RoomAliasId>,
///         }
///     }
/// }
/// # }
/// ```
///
/// Occasionally an event will have non-standard fields at its top level (outside the `content`
/// field). These extra fields are declared in block labeled with `fields`:
///
/// ```ignore
/// # pub mod example {
/// # use ruma_events_macros::ruma_event;
/// ruma_event! {
///     /// A redaction of an event.
///     RedactionEvent {
///         kind: RoomEvent,
///         event_type: RoomRedaction,
///         fields: {
///             /// The ID of the event that was redacted.
///             pub redacts: ruma_identifiers::EventId
///         },
///         content: {
///             /// The reason for the redaction, if any.
///             pub reason: Option<String>,
///         },
///     }
/// }
/// # }
/// ```
///
/// Sometimes the type of the `content` should be a type alias rather than a struct or enum. This
/// is designated with `content_type_alias`:
///
/// ```ignore
/// # pub mod example {
/// # use ruma_events_macros::ruma_event;
/// ruma_event! {
///     /// Informs the client about the rooms that are considered direct by a user.
///     DirectEvent {
///         kind: Event,
///         event_type: Direct,
///         content_type_alias: {
///             /// The payload of a `DirectEvent`.
///             ///
///             /// A mapping of `UserId`'s to a collection of `RoomId`'s which are considered
///             /// *direct* for that particular user.
///             std::collections::HashMap<ruma_identifiers::UserId, Vec<ruma_identifiers::RoomId>>
///         }
///     }
/// }
/// # }
/// ```
///
/// If `content` and `content_type_alias` are both supplied, the second one listed will overwrite
/// the first.
///
/// The event type and content type will have copies generated inside a private `raw` module. These
/// "raw" versions are the same, except they implement `serde::Deserialize`. An implementation of
/// `FromRaw` will be provided, which will allow the user to deserialize the event type as
/// `EventResult<EventType>`.
#[proc_macro]
pub fn ruma_event(input: TokenStream) -> TokenStream {
    let ruma_event_input = syn::parse_macro_input!(input as RumaEventInput);

    let ruma_event = RumaEvent::from(ruma_event_input);

    ruma_event.into_token_stream().into()
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::env::{current_dir, vars};
use std::io::{self, Write};

use anyhow::{bail, Context, Result};
use log::error;

use pueue::message::*;
use pueue::platform::socket::*;
use pueue::protocol::*;
use pueue::settings::Settings;

use crate::cli::{CliArguments, SubCommand};
use crate::commands::edit::*;
use crate::commands::local_follow::*;
use crate::commands::restart::*;
use crate::output::*;

/// This struct contains the base logic for the client.
/// The client is responsible for connecting to the daemon, sending instructions
/// and interpreting their responses.
///
/// Most commands are a simple ping-pong. However, some commands require a more complex
/// communication pattern, such as the `follow` command, which continuously streams the output of a task.
pub struct Client {
    opt: CliArguments,
    settings: Settings,
    socket: Socket,
}

impl Client {
    /// Connect to the daemon, authorize via secret and return a new initialized Client.
    pub async fn new(settings: Settings, opt: CliArguments) -> Result<Self> {
        // // Commandline argument overwrites the configuration files values for address
        // let address = if let Some(address) = opt.address.clone() {
        //     address
        // } else {
        //     settings.client.daemon_address
        // };

        // Commandline argument overwrites the configuration files values for port
        let (unix_socket_path, port) = {
            // Always prefer commandline options
            if let Some(path) = opt.unix_socket_path.clone() {
                (Some(path), None)
            } else if let Some(port) = opt.port.clone() {
                (None, Some(port))
            } else if settings.shared.use_unix_socket {
                (Some(settings.shared.unix_socket_path.clone()), None)
            } else {
                (None, Some(settings.shared.port.clone()))
            }
        };

        let mut socket = get_client(unix_socket_path, port).await?;

        // Send the secret to the daemon
        // In case everything was successful, we get a short `hello` response from the daemon.
        let secret = settings.shared.secret.clone().into_bytes();
        send_bytes(&secret, &mut socket).await?;
        let hello = receive_bytes(&mut socket).await?;
        if hello != b"hello" {
            bail!("Daemon went away after initial connection. Did you use the correct secret?")
        }

        Ok(Client {
            opt,
            settings,
            socket,
        })
    }

    /// This is the function where the actual communication and logic starts.
    /// At this point everything is initialized, the connection is up and
    /// we can finally start doing stuff.
    ///
    /// The command handling is splitted into "simple" and "complex" commands.
    pub async fn start(&mut self) -> Result<()> {
        // Return early, if the command has already been handled.
        if self.handle_complex_command().await? {
            return Ok(());
        }

        // The handling of "generic" commands is encapsulated in this function.
        self.handle_simple_command().await?;

        Ok(())
    }

    /// Handle all complex client-side functionalities.
    /// Complex functionalities need some special handling and are contained
    /// in their own functions with their own communication code.
    /// Such functionalities includes reading local files, data streaming
    /// and sending multiple messages.
    ///
    /// Returns `true`, if the current command has been handled by this function.
    /// This indicates that the client can now shut down.
    async fn handle_complex_command(&mut self) -> Result<bool> {
        // This match handles all "complex" commands.
        match &self.opt.cmd {
            SubCommand::Edit { task_id, path } => {
                let message = edit(&mut self.socket, *task_id, *path).await?;
                self.handle_response(message);
                Ok(true)
            }
            SubCommand::Restart {
                task_ids,
                start_immediately,
                stashed,
                edit,
                path,
            } => {
                restart(
                    &mut self.socket,
                    task_ids.clone(),
                    *start_immediately,
                    *stashed,
                    *edit,
                    *path,
                )
                .await?;
                Ok(true)
            }
            SubCommand::Follow { task_id, err } => {
                // Simple log output follows for local logs don't need any communication with the daemon.
                // Thereby we handle this separately over here.
                if self.settings.client.read_local_logs {
                    local_follow(
                        &mut self.socket,
                        self.settings.shared.pueue_directory.clone(),
                        task_id,
                        *err,
                    )
                    .await?;
                    return Ok(true);
                }
                Ok(false)
            }
            _ => Ok(false),
        }
    }

    /// Handle logic that's super generic on the client-side.
    /// This always follows a singular ping-pong pattern.
    /// One message to the daemon, one response, Done.
    async fn handle_simple_command(&mut self) -> Result<()> {
        // Create the message that should be sent to the daemon
        // depending on the given commandline options.
        let message = self.get_message_from_opt()?;

        // Create the message payload and send it to the daemon.
        send_message(message, &mut self.socket).await?;

        // Check if we can receive the response from the daemon
        let mut response = receive_message(&mut self.socket).await?;

        // Check if we can receive the response from the daemon
        while self.handle_response(response) {
            response = receive_message(&mut self.socket).await?;
        }

        Ok(())
    }

    /// Most returned messages can be handled in a generic fashion.
    /// However, some commands require continuous receiving of messages (streaming).
    ///
    /// If this function returns `Ok(true)`, the parent function will continue to receive
    /// and handle messages from the daemon. Otherwise the client will simply exit.
    fn handle_response(&self, message: Message) -> bool {
        match message {
            Message::Success(text) => print_success(&text),
            Message::Failure(text) => print_error(&text),
            Message::StatusResponse(state) => print_state(state, &self.opt.cmd, &self.settings),
            Message::LogResponse(task_logs) => print_logs(task_logs, &self.opt.cmd, &self.settings),
            Message::Stream(text) => {
                print!("{}", text);
                io::stdout().flush().unwrap();
                return true;
            }
            _ => error!("Received unhandled response message"),
        };

        false
    }

    /// Prints a warning and prompt for given action and tasks.
    /// Returns `Ok(())` if the action was confirmed.
    fn handle_user_confirmation(&self, action: &str, task_ids: &[usize]) -> Result<()> {
        // printing warning and prompt
        println!(
            "You are trying to {}: {}",
            action,
            task_ids
                .iter()
                .map(|t| format!("task{}", t.to_string()))
                .collect::<Vec<String>>()
                .join(", ")
        );

        let mut input = String::new();

        loop {
            print!("Do you want to continue [Y/n]: ");
            io::stdout().flush().unwrap();
            input.clear();
            io::stdin().read_line(&mut input)?;

            match input.chars().next().unwrap() {
                'N' | 'n' => {
                    println!("Aborted!");
                    std::process::exit(1);
                }
                '\n' | 'Y' | 'y' => {
                    break;
                }
                _ => {
                    continue;
                }
            }
        }

        Ok(())
    }

    /// Convert the cli command into the message that's being sent to the server,
    /// so it can be understood by the daemon.
    fn get_message_from_opt(&self) -> Result<Message> {
        match &self.opt.cmd {
            SubCommand::Add {
                command,
                start_immediately,
                stashed,
                group,
                delay_until,
                dependencies,
            } => {
                let cwd_pathbuf = current_dir()?;
                let cwd = cwd_pathbuf
                    .to_str()
                    .context("Cannot parse current working directory (Invalid utf8?)")?;

                let mut envs = HashMap::new();
                // Save all environment variables for later injection into the started task
                for (key, value) in vars() {
                    envs.insert(key, value);
                }

                Ok(Message::Add(AddMessage {
                    command: command.join(" "),
                    path: cwd.to_string(),
                    envs,
                    start_immediately: *start_immediately,
                    stashed: *stashed,
                    group: group.clone(),
                    enqueue_at: *delay_until,
                    dependencies: dependencies.to_vec(),
                    ignore_aliases: false,
                }))
            }
            SubCommand::Remove { task_ids } => {
                if self.settings.client.show_confirmation_questions {
                    self.handle_user_confirmation("remove", task_ids)?;
                }
                Ok(Message::Remove(task_ids.clone()))
            }
            SubCommand::Stash { task_ids } => Ok(Message::Stash(task_ids.clone())),
            SubCommand::Switch {
                task_id_1,
                task_id_2,
            } => {
                let message = SwitchMessage {
                    task_id_1: *task_id_1,
                    task_id_2: *task_id_2,
                };
                Ok(Message::Switch(message))
            }
            SubCommand::Enqueue {
                task_ids,
                delay_until,
            } => {
                let message = EnqueueMessage {
                    task_ids: task_ids.clone(),
                    enqueue_at: *delay_until,
                };
                Ok(Message::Enqueue(message))
            }
            SubCommand::Start {
                task_ids,
                group,
                all,
                children,
            } => {
                let message = StartMessage {
                    task_ids: task_ids.clone(),
                    group: group.clone(),
                    all: *all,
                    children: *children,
                };
                Ok(Message::Start(message))
            }
            SubCommand::Pause {
                task_ids,
                group,
                wait,
                all,
                children,
            } => {
                let message = PauseMessage {
                    task_ids: task_ids.clone(),
                    group: group.clone(),
                    wait: *wait,
                    all: *all,
                    children: *children,
                };
                Ok(Message::Pause(message))
            }
            SubCommand::Kill {
                task_ids,
                group,
                default,
                all,
                children,
            } => {
                if self.settings.client.show_confirmation_questions {
                    self.handle_user_confirmation("kill", task_ids)?;
                }
                let message = KillMessage {
                    task_ids: task_ids.clone(),
                    group: group.clone(),
                    default: *default,
                    all: *all,
                    children: *children,
                };
                Ok(Message::Kill(message))
            }
            SubCommand::Send { task_id, input } => {
                let message = SendMessage {
                    task_id: *task_id,
                    input: input.clone(),
                };
                Ok(Message::Send(message))
            }
            SubCommand::Group { add, remove } => {
                let message = GroupMessage {
                    add: add.clone(),
                    remove: remove.clone(),
                };
                Ok(Message::Group(message))
            }
            SubCommand::Status { .. } => Ok(Message::Status),
            SubCommand::Log { task_ids, .. } => {
                let message = LogRequestMessage {
                    task_ids: task_ids.clone(),
                    send_logs: !self.settings.client.read_local_logs,
                };
                Ok(Message::Log(message))
            }
            SubCommand::Follow { task_id, err } => {
                let message = StreamRequestMessage {
                    task_id: *task_id,
                    err: *err,
                };
                Ok(Message::StreamRequest(message))
            }
            SubCommand::Clean => Ok(Message::Clean),
            SubCommand::Reset { children } => Ok(Message::Reset(*children)),
            SubCommand::Shutdown => Ok(Message::DaemonShutdown),
            SubCommand::Parallel {
                parallel_tasks,
                group,
            } => {
                let message = ParallelMessage {
                    parallel_tasks: *parallel_tasks,
                    group: group.clone(),
                };
                Ok(Message::Parallel(message))
            }
            SubCommand::Completions { .. } => bail!("Completions have to be handled earlier"),
            SubCommand::Restart { .. } => bail!("Restarts have to be handled earlier"),
            SubCommand::Edit { .. } => bail!("Edits have to be handled earlier"),
        }
    }
}
<commit_msg>Adjust some comments<commit_after>use std::collections::HashMap;
use std::env::{current_dir, vars};
use std::io::{self, Write};

use anyhow::{bail, Context, Result};
use log::error;

use pueue::message::*;
use pueue::platform::socket::*;
use pueue::protocol::*;
use pueue::settings::Settings;

use crate::cli::{CliArguments, SubCommand};
use crate::commands::edit::*;
use crate::commands::local_follow::*;
use crate::commands::restart::*;
use crate::output::*;

/// This struct contains the base logic for the client.
/// The client is responsible for connecting to the daemon, sending instructions
/// and interpreting their responses.
///
/// Most commands are a simple ping-pong. However, some commands require a more complex
/// communication pattern, such as the `follow` command, which can read local files,
/// or the `edit` command, which needs to open an editor locally.
pub struct Client {
    opt: CliArguments,
    settings: Settings,
    socket: Socket,
}

impl Client {
    /// Connect to the daemon, authorize via secret and return a new initialized Client.
    pub async fn new(settings: Settings, opt: CliArguments) -> Result<Self> {
        // // Commandline argument overwrites the configuration files values for address
        // let address = if let Some(address) = opt.address.clone() {
        //     address
        // } else {
        //     settings.client.daemon_address
        // };

        // Commandline argument overwrites the configuration files values for port
        let (unix_socket_path, port) = {
            // Always prefer commandline options
            if let Some(path) = opt.unix_socket_path.clone() {
                (Some(path), None)
            } else if let Some(port) = opt.port.clone() {
                (None, Some(port))
            } else if settings.shared.use_unix_socket {
                (Some(settings.shared.unix_socket_path.clone()), None)
            } else {
                (None, Some(settings.shared.port.clone()))
            }
        };

        let mut socket = get_client(unix_socket_path, port).await?;

        // Send the secret to the daemon
        // In case everything was successful, we get a short `hello` response from the daemon.
        let secret = settings.shared.secret.clone().into_bytes();
        send_bytes(&secret, &mut socket).await?;
        let hello = receive_bytes(&mut socket).await?;
        if hello != b"hello" {
            bail!("Daemon went away after initial connection. Did you use the correct secret?")
        }

        Ok(Client {
            opt,
            settings,
            socket,
        })
    }

    /// This is the function where the actual communication and logic starts.
    /// At this point everything is initialized, the connection is up and
    /// we can finally start doing stuff.
    ///
    /// The command handling is splitted into "simple" and "complex" commands.
    pub async fn start(&mut self) -> Result<()> {
        // Return early, if the command has already been handled.
        if self.handle_complex_command().await? {
            return Ok(());
        }

        // The handling of "generic" commands is encapsulated in this function.
        self.handle_simple_command().await?;

        Ok(())
    }

    /// Handle all complex client-side functionalities.
    /// Complex functionalities need some special handling and are contained
    /// in their own functions with their own communication code.
    /// Such functionalities includes reading local filestand sending multiple messages.
    ///
    /// Returns `true`, if the current command has been handled by this function.
    /// This indicates that the client can now shut down.
    async fn handle_complex_command(&mut self) -> Result<bool> {
        // This match handles all "complex" commands.
        match &self.opt.cmd {
            SubCommand::Edit { task_id, path } => {
                let message = edit(&mut self.socket, *task_id, *path).await?;
                self.handle_response(message);
                Ok(true)
            }
            SubCommand::Restart {
                task_ids,
                start_immediately,
                stashed,
                edit,
                path,
            } => {
                restart(
                    &mut self.socket,
                    task_ids.clone(),
                    *start_immediately,
                    *stashed,
                    *edit,
                    *path,
                )
                .await?;
                Ok(true)
            }
            SubCommand::Follow { task_id, err } => {
                // Simple log output follows for local logs don't need any communication with the daemon.
                // Thereby we handle this separately over here.
                if self.settings.client.read_local_logs {
                    local_follow(
                        &mut self.socket,
                        self.settings.shared.pueue_directory.clone(),
                        task_id,
                        *err,
                    )
                    .await?;
                    return Ok(true);
                }
                Ok(false)
            }
            _ => Ok(false),
        }
    }

    /// Handle logic that's super generic on the client-side.
    /// This (almost) always follows a singular ping-pong pattern.
    /// One message to the daemon, one response, Done.
    ///
    /// The only exception is streaming of log output.
    /// In that case, we send one request and contine receiving until the socket shuts down.
    async fn handle_simple_command(&mut self) -> Result<()> {
        // Create the message that should be sent to the daemon
        // depending on the given commandline options.
        let message = self.get_message_from_opt()?;

        // Create the message payload and send it to the daemon.
        send_message(message, &mut self.socket).await?;

        // Check if we can receive the response from the daemon
        let mut response = receive_message(&mut self.socket).await?;

        // Check if we can receive the response from the daemon
        while self.handle_response(response) {
            response = receive_message(&mut self.socket).await?;
        }

        Ok(())
    }

    /// Most returned messages can be handled in a generic fashion.
    /// However, some commands require continuous receiving of messages (streaming).
    ///
    /// If this function returns `Ok(true)`, the parent function will continue to receive
    /// and handle messages from the daemon. Otherwise the client will simply exit.
    fn handle_response(&self, message: Message) -> bool {
        match message {
            Message::Success(text) => print_success(&text),
            Message::Failure(text) => print_error(&text),
            Message::StatusResponse(state) => print_state(state, &self.opt.cmd, &self.settings),
            Message::LogResponse(task_logs) => print_logs(task_logs, &self.opt.cmd, &self.settings),
            Message::Stream(text) => {
                print!("{}", text);
                io::stdout().flush().unwrap();
                return true;
            }
            _ => error!("Received unhandled response message"),
        };

        false
    }

    /// Prints a warning and prompt for given action and tasks.
    /// Returns `Ok(())` if the action was confirmed.
    fn handle_user_confirmation(&self, action: &str, task_ids: &[usize]) -> Result<()> {
        // printing warning and prompt
        println!(
            "You are trying to {}: {}",
            action,
            task_ids
                .iter()
                .map(|t| format!("task{}", t.to_string()))
                .collect::<Vec<String>>()
                .join(", ")
        );

        let mut input = String::new();

        loop {
            print!("Do you want to continue [Y/n]: ");
            io::stdout().flush().unwrap();
            input.clear();
            io::stdin().read_line(&mut input)?;

            match input.chars().next().unwrap() {
                'N' | 'n' => {
                    println!("Aborted!");
                    std::process::exit(1);
                }
                '\n' | 'Y' | 'y' => {
                    break;
                }
                _ => {
                    continue;
                }
            }
        }

        Ok(())
    }

    /// Convert the cli command into the message that's being sent to the server,
    /// so it can be understood by the daemon.
    fn get_message_from_opt(&self) -> Result<Message> {
        match &self.opt.cmd {
            SubCommand::Add {
                command,
                start_immediately,
                stashed,
                group,
                delay_until,
                dependencies,
            } => {
                let cwd_pathbuf = current_dir()?;
                let cwd = cwd_pathbuf
                    .to_str()
                    .context("Cannot parse current working directory (Invalid utf8?)")?;

                let mut envs = HashMap::new();
                // Save all environment variables for later injection into the started task
                for (key, value) in vars() {
                    envs.insert(key, value);
                }

                Ok(Message::Add(AddMessage {
                    command: command.join(" "),
                    path: cwd.to_string(),
                    envs,
                    start_immediately: *start_immediately,
                    stashed: *stashed,
                    group: group.clone(),
                    enqueue_at: *delay_until,
                    dependencies: dependencies.to_vec(),
                    ignore_aliases: false,
                }))
            }
            SubCommand::Remove { task_ids } => {
                if self.settings.client.show_confirmation_questions {
                    self.handle_user_confirmation("remove", task_ids)?;
                }
                Ok(Message::Remove(task_ids.clone()))
            }
            SubCommand::Stash { task_ids } => Ok(Message::Stash(task_ids.clone())),
            SubCommand::Switch {
                task_id_1,
                task_id_2,
            } => {
                let message = SwitchMessage {
                    task_id_1: *task_id_1,
                    task_id_2: *task_id_2,
                };
                Ok(Message::Switch(message))
            }
            SubCommand::Enqueue {
                task_ids,
                delay_until,
            } => {
                let message = EnqueueMessage {
                    task_ids: task_ids.clone(),
                    enqueue_at: *delay_until,
                };
                Ok(Message::Enqueue(message))
            }
            SubCommand::Start {
                task_ids,
                group,
                all,
                children,
            } => {
                let message = StartMessage {
                    task_ids: task_ids.clone(),
                    group: group.clone(),
                    all: *all,
                    children: *children,
                };
                Ok(Message::Start(message))
            }
            SubCommand::Pause {
                task_ids,
                group,
                wait,
                all,
                children,
            } => {
                let message = PauseMessage {
                    task_ids: task_ids.clone(),
                    group: group.clone(),
                    wait: *wait,
                    all: *all,
                    children: *children,
                };
                Ok(Message::Pause(message))
            }
            SubCommand::Kill {
                task_ids,
                group,
                default,
                all,
                children,
            } => {
                if self.settings.client.show_confirmation_questions {
                    self.handle_user_confirmation("kill", task_ids)?;
                }
                let message = KillMessage {
                    task_ids: task_ids.clone(),
                    group: group.clone(),
                    default: *default,
                    all: *all,
                    children: *children,
                };
                Ok(Message::Kill(message))
            }
            SubCommand::Send { task_id, input } => {
                let message = SendMessage {
                    task_id: *task_id,
                    input: input.clone(),
                };
                Ok(Message::Send(message))
            }
            SubCommand::Group { add, remove } => {
                let message = GroupMessage {
                    add: add.clone(),
                    remove: remove.clone(),
                };
                Ok(Message::Group(message))
            }
            SubCommand::Status { .. } => Ok(Message::Status),
            SubCommand::Log { task_ids, .. } => {
                let message = LogRequestMessage {
                    task_ids: task_ids.clone(),
                    send_logs: !self.settings.client.read_local_logs,
                };
                Ok(Message::Log(message))
            }
            SubCommand::Follow { task_id, err } => {
                let message = StreamRequestMessage {
                    task_id: *task_id,
                    err: *err,
                };
                Ok(Message::StreamRequest(message))
            }
            SubCommand::Clean => Ok(Message::Clean),
            SubCommand::Reset { children } => Ok(Message::Reset(*children)),
            SubCommand::Shutdown => Ok(Message::DaemonShutdown),
            SubCommand::Parallel {
                parallel_tasks,
                group,
            } => {
                let message = ParallelMessage {
                    parallel_tasks: *parallel_tasks,
                    group: group.clone(),
                };
                Ok(Message::Parallel(message))
            }
            SubCommand::Completions { .. } => bail!("Completions have to be handled earlier"),
            SubCommand::Restart { .. } => bail!("Restarts have to be handled earlier"),
            SubCommand::Edit { .. } => bail!("Edits have to be handled earlier"),
        }
    }
}
<|endoftext|>