/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::cmp;
use std::collections::HashMap;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fs;
use std::fs::File;
use std::panic;
use std::path::PathBuf;
use std::sync::Arc;

use crossbeam::queue::SegQueue;
use dice::introspection::serialize_dense_graph;
use dice::DetectCycles;
use dice::Dice;
use dice::DiceTransaction;
use dupe::Dupe;
use futures::FutureExt;
use itertools::Itertools;
use parking_lot::Mutex;
use quickcheck::Arbitrary;
use quickcheck::Gen;
use quickcheck::TestResult;
use serde::Deserialize;
use serde::Serialize;
use serde::Serializer;
use uuid::Uuid;

use crate::computation::ComputationStep;
use crate::computation::Expr;
use crate::computation::FuzzEquations;
use crate::computation::FuzzMath;
use crate::computation::FuzzState;
use crate::computation::Unit;
use crate::computation::Var;

/// For a given DiceExecutionOrder that includes some Queries, computes the
/// expected result of each of those queries.
/// A result of None indicates the computation is expected to fail or panic.
struct MathAnswerKey {
    values_by_ctx_id: HashMap<usize, HashMap<Var, Option<bool>>>,
}

impl MathAnswerKey {
    pub fn new(order: &DiceExecutionOrder) -> Self {
        // Pre-process the execution order to see which computations will be requested.
        let queried_vars_by_ctx_id = Self::queried_vars_by_ctx_id(order);
        // Maintain the current set of exprs.
        let mut exprs = HashMap::new();
        let mut values_by_ctx_id: HashMap<usize, HashMap<Var, Option<bool>>> = HashMap::new();
        for op in order.init_vars.iter().chain(order.timeline.iter()) {
            match op {
                Operation::SetValue {
                    new_ctx_id,
                    var,
                    expr,
                } => {
                    exprs.insert(*var, expr.clone());
                    if let Some(queried_vars) = queried_vars_by_ctx_id.get(new_ctx_id) {
                        values_by_ctx_id.insert(
                            *new_ctx_id,
                            queried_vars
                                .iter()
                                .map(|v| (*v, Self::eval(*v, &exprs)))
                                .collect(),
                        );
                    }
                }
                Operation::Query { .. } => (),
                Operation::EnqueueStep(..) => (),
            }
        }
        Self { values_by_ctx_id }
    }

    pub fn value_of_at_ctx(&self, ctx_id: usize, var: Var) -> Option<bool> {
        self.values_by_ctx_id
            .get(&ctx_id)
            .and_then(|map| map.get(&var))
            .copied()
            .unwrap_or(None)
    }

    fn queried_vars_by_ctx_id(order: &DiceExecutionOrder) -> HashMap<usize, Vec<Var>> {
        let mut queried_vars_by_ctx_id: HashMap<usize, Vec<Var>> = HashMap::new();
        for op in order.timeline.iter() {
            if let Operation::Query { ctx_id, var } = op {
                queried_vars_by_ctx_id
                    .entry(*ctx_id)
                    .or_insert_with(std::vec::Vec::new)
                    .push(*var);
            }
        }
        queried_vars_by_ctx_id
    }

    fn resolve_unit(unit: &Unit, exprs: &HashMap<Var, Expr>) -> Option<bool> {
        match unit {
            Unit::Variable(var) => Self::eval(*var, exprs),
            Unit::Literal(lit) => Some(*lit),
        }
    }

    fn eval(var: Var, exprs: &HashMap<Var, Expr>) -> Option<bool> {
        exprs.get(&var).and_then(|expr| match expr {
            Expr::Unit(unit) => Self::resolve_unit(unit, exprs),
            Expr::Cond {
                test,
                then,
                otherwise,
            } => {
                if Self::resolve_unit(test, exprs)? {
                    Self::resolve_unit(then, exprs)
                } else {
                    Self::resolve_unit(otherwise, exprs)
                }
            }
            Expr::Xor(vars) => vars
                .iter()
                .map(|x| Self::resolve_unit(x, exprs))
                .collect::<Option<Vec<_>>>()
                .map(|bools| bools.into_iter().reduce(|x, y| x ^ y).unwrap_or(false)),
        })
    }
}

enum ExecutionResult {
    Correct,
    IncorrectResult { expected: bool, actual: bool },
    ExpectedPanic(bool),
    UnexpectedPanic(String),
}

impl Display for ExecutionResult {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            ExecutionResult::Correct => {
                write!(f, "Correct")
            }
            ExecutionResult::IncorrectResult { expected, actual } => {
                write!(f, "Expected `{}` but got `{}`", expected, actual)
            }
            ExecutionResult::ExpectedPanic(res) => {
                write!(
                    f,
                    "Expected panic from injected key missing but got `{}`",
                    res
                )
            }
            ExecutionResult::UnexpectedPanic(p) => {
                write!(f, "Expected result but panicked `{}`", p)
            }
        }
    }
}

#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Operation {
    /// Evaluate the variable at the version immediately after
    /// the SetValue op with this ctx_id.
    Query { ctx_id: usize, var: Var },
    /// Set the injected key corresponding to this variable.
    SetValue {
        new_ctx_id: usize,
        var: Var,
        expr: Expr,
    },
    /// Force the next evaluation of this var to do something other than just
    /// returning the correct result (e.g. force DICE to treat the value as
    /// transient).
    /// For now, this can't change the boolean result of the eval, since
    /// that'll break our ability to check DICE's computations are correct.
    EnqueueStep(Var, Vec<ComputationStep>),
}

fn uuid_serializer<S>(uuid: &Uuid, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
{
    serializer.serialize_str(&uuid.to_string())
}

#[derive(Clone, Serialize, Deserialize)]
pub struct DiceExecutionOrder {
    #[serde(skip_deserializing, serialize_with = "uuid_serializer")]
    pub uuid: Uuid,
    /// A list of operations that initialize each var, in order, to a literal.
    init_vars: Vec<Operation>,
    /// A list of updates, queries, and enqueued "steps" that tweak computation.
    /// Notably, this doesn't introduce new vars, to simplify the shrink() implementation.
    timeline: Vec<Operation>,
    /// Are we shrinking an already-found failure? See comment in |execute|.
    is_shrinking: bool,
    /// The first failure we encountered
    #[serde(skip)]
    first_failure: Arc<Mutex<Option<Arc<ExecutionResult>>>>,
}

impl Debug for DiceExecutionOrder {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", serde_json::to_string_pretty(self).unwrap())
    }
}

pub struct DiceExecutionOrderOptions {
    pub print_dumps: Option<PathBuf>,
}

static ALL_PANICS: Mutex<Vec<String>> = parking_lot::const_mutex(Vec::new());

impl DiceExecutionOrder {
    const NSAMPLES_SEARCHING: usize = 1;
    const NSAMPLES_SHRINKING: usize = 100;
    const AVG_OPS_PER_VAR: usize = 4;
    const VARS_PER_XOR: usize = 5;

    fn make_failure(&self, msg: String) -> TestResult {
        TestResult::error(format!("Execution: {:?}\nFailure: `{}`", self, msg))
    }

    /// If a repro is nondeterministic, shrunk testcases that contain the
    /// same bug may not repro, so shrinking might stop early.
    /// Since shrinking a big testcase takes multiple consecutive failures,
    /// without multiple samples, shrinking will usually stop early.
    pub async fn execute(&self, options: &DiceExecutionOrderOptions) -> TestResult {
        let answer_key = MathAnswerKey::new(self);
        let ntimes = if self.is_shrinking {
            Self::NSAMPLES_SHRINKING
        } else {
            Self::NSAMPLES_SEARCHING
        };

        let mut ignored_failure = vec![];
        for run_count in 0..ntimes {
            match self.execute_once(&answer_key, run_count, options).await {
                ExecutionResult::Correct => {}
                ExecutionResult::ExpectedPanic(r) => {
                    let mut first_failure = self.first_failure.lock();
                    match &*first_failure {
                        None => {
                            *first_failure = Some(Arc::new(ExecutionResult::ExpectedPanic(r)));
                            return self.make_failure(first_failure.as_ref().unwrap().to_string());
                        }
                        Some(prev) => {
                            match &**prev {
                                ExecutionResult::ExpectedPanic(prev_r) if *prev_r == r => {
                                    return self.make_failure(prev.to_string());
                                }
                                _ => {
                                    // keep going because the error doesn't match
                                    ignored_failure.push(ExecutionResult::ExpectedPanic(r))
                                }
                            }
                        }
                    }
                }
                ExecutionResult::IncorrectResult { expected, actual } => {
                    let mut first_failure = self.first_failure.lock();
                    match &*first_failure {
                        None => {
                            *first_failure = Some(Arc::new(ExecutionResult::IncorrectResult {
                                expected,
                                actual,
                            }));
                            return self.make_failure(first_failure.as_ref().unwrap().to_string());
                        }
                        Some(prev) => match &**prev {
                            ExecutionResult::IncorrectResult {
                                expected: prev_expected,
                                actual: prev_actual,
                            } if *prev_expected == expected && *prev_actual == actual => {
                                return self.make_failure(prev.to_string());
                            }
                            _ => ignored_failure
                                .push(ExecutionResult::IncorrectResult { expected, actual }),
                        },
                    }
                }
                ExecutionResult::UnexpectedPanic(p) => {
                    let mut first_failure = self.first_failure.lock();
                    match &*first_failure {
                        None => {
                            *first_failure = Some(Arc::new(ExecutionResult::UnexpectedPanic(p)));
                            return self.make_failure(first_failure.as_ref().unwrap().to_string());
                        }
                        Some(prev) => {
                            match &**prev {
                                ExecutionResult::UnexpectedPanic(_) => {
                                    return self.make_failure(prev.to_string());
                                }
                                _ => {
                                    // keep going because the error doesn't match
                                    ignored_failure.push(ExecutionResult::UnexpectedPanic(p))
                                }
                            }
                        }
                    }
                }
            }

            if let Some(dump_loc) = self.get_dump_dir(options) {
                // we don't keep dump of any runs that are not a failure
                fs::remove_dir_all(dump_loc.join(format!("run-{}", run_count)))
                    .expect("failed to remove dump");
            }
        }

        if self.first_failure.lock().is_some() && !ignored_failure.is_empty() {
            // we were supposed to find a particular failure but we didn't.
            eprintln!(
                "warning: supposed to find a specific error `{}` but didn't find any",
                self.first_failure.lock().as_ref().unwrap()
            );
            return TestResult::discard();
        }

        TestResult::passed()
    }

    async fn execute_once(
        &self,
        answer_key: &MathAnswerKey,
        run_count: usize,
        options: &DiceExecutionOrderOptions,
    ) -> ExecutionResult {
        let dice = Dice::builder().build(DetectCycles::Disabled);
        let mut dice_ctxs: HashMap<usize, DiceTransaction> = HashMap::new();
        let state = {
            let mut state = FuzzState::new();
            for var in self.init_vars.iter().map(|op| match &op {
                Operation::Query { var, .. } => var,
                Operation::SetValue { var, .. } => var,
                Operation::EnqueueStep(var, _) => var,
            }) {
                state.steps.entry(*var).or_insert_with(SegQueue::new);
            }
            Arc::new(state)
        };
        for (step_count, op) in self
            .init_vars
            .iter()
            .chain(self.timeline.iter())
            .enumerate()
        {
            match &op {
                Operation::Query { ctx_id, var } => {
                    if let Some(ctx) = dice_ctxs.get(ctx_id) {
                        let expected = answer_key.value_of_at_ctx(*ctx_id, *var);

                        // quickcheck runs us single threaded, so this is safe to do.
                        let old_handler = panic::take_hook();

                        ALL_PANICS.lock().clear();
                        // suppress print panics from dice.
                        panic::set_hook(Box::new(|info| {
                            ALL_PANICS.lock().push(
                                if let Some(s) = info.payload().downcast_ref::<&str>() {
                                    (*s).to_owned()
                                } else if let Some(s) = info.payload().downcast_ref::<String>() {
                                    s.clone()
                                } else {
                                    "unknown".to_owned()
                                },
                            )
                            // do nothing. don't print because we have panics that we expect.
                            // they get spammed on the console such that the info we do print
                            // gets washed away. Hiding the panics makes the information we do
                            // print much more useful.
                        }));

                        let exec_result = std::panic::AssertUnwindSafe(async {
                            ctx.eval(state.dupe(), *var).await.expect("eval errored")
                        })
                        .catch_unwind()
                        .await;

                        panic::set_hook(old_handler);

                        if exec_result.is_ok() && !ALL_PANICS.lock().is_empty() {
                            // we panicked on a thread that wasn't joined.
                            // This is still wrong.
                            return ExecutionResult::UnexpectedPanic(
                                ALL_PANICS
                                    .lock()
                                    .iter()
                                    .map(|panic| format!("panic: `{}`", panic))
                                    .join("\n"),
                            );
                        }

                        match (expected, exec_result) {
                            (Some(expected), Ok(result)) => {
                                if expected != result {
                                    return ExecutionResult::IncorrectResult {
                                        expected,
                                        actual: result,
                                    };
                                }
                            }
                            (Some(_), Err(panic)) => {
                                if std::env::var("ALLOW_INCORRECT_WHEN_SHOULD_PANIC").is_err() {
                                    // There's a known bug where DICE sometimes uses injected keys from versions prior to the current query.
                                    // These computations should panic, but don't, and the fuzzer keeps finding them.
                                    // This environment variable disables this class of bugs, so other errors are easier to find.
                                    return ExecutionResult::UnexpectedPanic(
                                        if let Some(s) = panic.downcast_ref::<&str>() {
                                            (*s).to_owned()
                                        } else if let Some(info) = panic.downcast_ref::<String>() {
                                            info.clone()
                                        } else {
                                            "unknown panic".to_owned()
                                        },
                                    );
                                }
                            }
                            (None, Err(_panic)) => {
                                // TODO maybe check the type of panic
                                if std::env::var("ALLOW_EXTRA_PANICS").is_err() {
                                    let panics = ALL_PANICS
                                        .lock()
                                        .iter()
                                        .filter(|panic| !panic.contains("spawned task cancelled"))
                                        .cloned()
                                        .collect::<Vec<_>>();

                                    if panics.len() > 1 {
                                        // we panicked on a thread that wasn't joined.
                                        // This is still wrong.
                                        return ExecutionResult::UnexpectedPanic(
                                            panics
                                                .iter()
                                                .map(|panic| format!("panic: `{}`", panic))
                                                .join("\n"),
                                        );
                                    }
                                }
                            }
                            (None, Ok(result)) => {
                                return ExecutionResult::ExpectedPanic(result);
                            }
                        }
                    }
                }
                Operation::SetValue {
                    new_ctx_id,
                    var,
                    expr,
                } => {
                    let mut ctx = dice.updater();
                    ctx.set_equation(*var, expr.clone()).unwrap();
                    dice_ctxs.insert(*new_ctx_id, ctx.commit().await);
                }
                Operation::EnqueueStep(var, steps) => {
                    let queue = state.steps.get(var).unwrap();
                    for step in steps {
                        queue.push(*step);
                    }
                }
            }

            self.maybe_dump_dice(options, run_count, step_count, &dice)
                .expect("couldn't dump DICE to disk");
        }

        ExecutionResult::Correct
    }

    pub fn get_dump_dir(&self, options: &DiceExecutionOrderOptions) -> Option<PathBuf> {
        options
            .print_dumps
            .as_ref()
            .map(|loc| loc.join(self.uuid.to_string()))
    }

    fn maybe_dump_dice(
        &self,
        options: &DiceExecutionOrderOptions,
        run_count: usize,
        step_count: usize,
        dice: &Arc<Dice>,
    ) -> anyhow::Result<()> {
        if let Some(loc) = self.get_dump_dir(options) {
            let dump_path = loc
                .join(format!("run-{}", run_count))
                .join(format!("step-{}", step_count));

            fs::create_dir_all(dump_path.parent().unwrap())?;
            let mut dump_loc = File::create(&dump_path)?;
            serialize_dense_graph(
                &dice.to_introspectable(),
                &mut serde_json::Serializer::pretty(&mut dump_loc),
            )?;
        }
        Ok(())
    }
}

impl Arbitrary for DiceExecutionOrder {
    fn arbitrary(g: &mut Gen) -> Self {
        let mut last_used_var = 0;
        let mut last_ctx_id = 0;
        let mut ctx_ids = vec![];
        let mut active_vars = vec![];
        let mut init_vars = vec![];
        let mut timeline = vec![];
        let mut var_values = Vec::<bool>::arbitrary(g);
        var_values.push(true); // Ensure non-empty.
        for val in var_values.iter() {
            last_ctx_id += 1;
            last_used_var += 1;
            ctx_ids.push(last_ctx_id);
            let var = Var(last_used_var);
            init_vars.push(Operation::SetValue {
                new_ctx_id: last_ctx_id,
                var,
                expr: Expr::Unit(Unit::Literal(*val)),
            });
            active_vars.push(var);
        }

        let select_var =
            |g: &mut Gen, vars: &[Var]| -> Unit { Unit::Variable(*g.choose(vars).unwrap()) };

        let arbitrary_expr = |g: &mut Gen, vars: &[Var]| -> Expr {
            if vars.is_empty() {
                return Expr::Unit(Unit::Literal(bool::arbitrary(g)));
            }
            // Semi-randomly select the expr type.
            match usize::arbitrary(g) % 100 {
                0..33 => Expr::Unit(Unit::Literal(bool::arbitrary(g))),
                34..66 => Expr::Xor({
                    let mut vec = Vec::new();
                    for _ in 0..Self::VARS_PER_XOR {
                        vec.push(select_var(g, vars))
                    }
                    vec
                }),
                _ => Expr::Cond {
                    test: select_var(g, vars),
                    then: select_var(g, vars),
                    otherwise: select_var(g, vars),
                },
            }
        };

        // There's a known bug in DICE involving transient values resulting in incorrect
        // computation. This environment variable disables the fuzzer searching for these
        // bugs, so other errors are easier to find.
        let gen_transients = std::env::var("NOGEN_TRANSIENTS").is_err();

        // don't generate any requests out of order
        let gen_out_of_order = std::env::var("NOGEN_OUT_OF_ORDER").is_err();

        for _ in 0..Self::AVG_OPS_PER_VAR * g.size() {
            let i = usize::arbitrary(g) % active_vars.len();
            // Semi-randomly select a next op.
            timeline.push(match usize::arbitrary(g) % 100 {
                0..40 => Operation::Query {
                    ctx_id: {
                        if gen_out_of_order {
                            *g.choose(&ctx_ids).unwrap()
                        } else {
                            cmp::max(ctx_ids.len() - 1, 0)
                        }
                    },
                    var: active_vars[i],
                },
                41..50 if gen_transients => Operation::EnqueueStep(
                    *g.choose(&active_vars).unwrap(),
                    vec![ComputationStep::ReturnTransient],
                ),
                _ => {
                    last_ctx_id += 1;
                    ctx_ids.push(last_ctx_id);
                    Operation::SetValue {
                        new_ctx_id: last_ctx_id,
                        var: active_vars[i],
                        // Avoid circularity by forcing a key to only depend on earlier keys.
                        expr: arbitrary_expr(g, &active_vars[0..i]),
                    }
                }
            });
        }
        DiceExecutionOrder {
            uuid: Uuid::new_v4(),
            is_shrinking: false,
            init_vars,
            timeline,
            first_failure: Arc::new(Mutex::new(None)),
        }
    }

    fn shrink(&self) -> Box<dyn Iterator<Item = Self>> {
        Box::new(DiceExecutionOrderShrinker::new(self.clone()))
    }
}

struct DiceExecutionOrderShrinker {
    pos: usize,
    seed: DiceExecutionOrder,
}

impl DiceExecutionOrderShrinker {
    fn new(seed: DiceExecutionOrder) -> Self {
        Self {
            pos: seed.timeline.len(),
            seed,
        }
    }
}

impl Iterator for DiceExecutionOrderShrinker {
    type Item = DiceExecutionOrder;

    fn next(&mut self) -> Option<Self::Item> {
        if self.pos == 0 {
            return None;
        }

        self.pos -= 1;
        Some(DiceExecutionOrder {
            uuid: Uuid::new_v4(),
            is_shrinking: true,
            init_vars: self.seed.init_vars.clone(),
            timeline: [
                &self.seed.timeline[0..self.pos],
                &self.seed.timeline[self.pos + 1..],
            ]
            .concat(),
            first_failure: self.seed.first_failure.dupe(),
        })
    }
}

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

    #[test]
    fn answer_key() {
        let order = DiceExecutionOrder {
            uuid: Default::default(),
            init_vars: vec![],
            timeline: vec![
                Operation::SetValue {
                    new_ctx_id: 1,
                    var: Var(1),
                    expr: Expr::Unit(Unit::Literal(true)),
                },
                Operation::SetValue {
                    new_ctx_id: 2,
                    var: Var(1),
                    expr: Expr::Unit(Unit::Literal(false)),
                },
                Operation::Query {
                    ctx_id: 1,
                    var: Var(1),
                },
                Operation::Query {
                    ctx_id: 2,
                    var: Var(1),
                },
                Operation::Query {
                    ctx_id: 1,
                    var: Var(2),
                },
            ],
            is_shrinking: false,
            first_failure: Arc::new(Mutex::new(None)),
        };
        let answer_key = MathAnswerKey::new(&order);
        // Two present and well-behaved query results.
        assert_eq!(Some(true), answer_key.value_of_at_ctx(1, Var(1)));
        assert_eq!(Some(false), answer_key.value_of_at_ctx(2, Var(1)));
        // A query of an injected key that hasn't been set yet should be None.
        assert_eq!(None, answer_key.value_of_at_ctx(1, Var(2)));
        // A never-queried result should be None.
        assert_eq!(None, answer_key.value_of_at_ctx(2, Var(2)));
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

#![feature(exclusive_range_pattern)]
#![feature(async_closure)]

use std::fs;
use std::fs::File;
use std::path::Path;
use std::path::PathBuf;

use anyhow::Context;
use clap::Args;
use clap::FromArgMatches;
use clap::Parser;
use quickcheck::Arbitrary;
use quickcheck::Gen;
use quickcheck::QuickCheck;
use quickcheck::TestResult;
use quickcheck::Testable;
use thiserror::Error;
use tracing_subscriber::fmt;
use tracing_subscriber::prelude::*;
use tracing_subscriber::EnvFilter;

mod computation;
mod execution;

use crate::execution::DiceExecutionOrder;
use crate::execution::DiceExecutionOrderOptions;

#[derive(Error, Debug)]
pub enum DiceFuzzError {
    #[error("couldn't parse provided replay file")]
    UnparsableReplay,
}

fn magical_cleanup(stderr: &str) -> anyhow::Result<&str> {
    // The last line of our output looks like (e.g.)
    // thread 'main' panicked at '[quickcheck] TEST FAILED. Arguments: ({"init_vars":[{"SetValue":{"new_ctx_id":1,"var":1,"expr":{"Unit":{"Literal":true}}}}],"timeline":[{"SetValue":{"new_ctx_id":3,"var":1,"expr":{"Unit":{"Literal":true}}}},{"Query":{"ctx_id":3,"var":1}},{"EnqueueStep":[1,["ReturnTransient"]]},{"EnqueueStep":[1,["ReturnTransient"]]},{"EnqueueStep":[1,["ReturnTransient"]]},{"Query":{"ctx_id":1,"var":1}},{"SetValue":{"new_ctx_id":9,"var":1,"expr":{"Unit":{"Literal":false}}}},{"SetValue":{"new_ctx_id":12,"var":1,"expr":{"Unit":{"Literal":true}}}},{"Query":{"ctx_id":9,"var":1}},{"Query":{"ctx_id":12,"var":1}},{"SetValue":{"new_ctx_id":14,"var":1,"expr":{"Unit":{"Literal":true}}}},{"SetValue":{"new_ctx_id":15,"var":1,"expr":{"Unit":{"Literal":true}}}},{"Query":{"ctx_id":15,"var":1}},{"Query":{"ctx_id":14,"var":1}},{"SetValue":{"new_ctx_id":17,"var":1,"expr":{"Unit":{"Literal":true}}}},{"Query":{"ctx_id":17,"var":1}}],"is_shrinking":true})', third-party/rust/vendor/quickcheck-1.0.3/src/tester.rs:165:28
    stderr
        .rsplit_once("TEST FAILED. Arguments: (")
        .and_then(|(_, suffix)| suffix.rsplit_once(')'))
        .map(|(prefix, _)| prefix)
        .ok_or_else(|| DiceFuzzError::UnparsableReplay.into())
}

fn execution_order_from_path(filepath: &Path) -> anyhow::Result<DiceExecutionOrder> {
    let buf = std::fs::read_to_string(filepath)?;
    if let Ok(ex) = serde_json::from_reader::<_, DiceExecutionOrder>(&mut buf.as_bytes()) {
        return Ok(ex);
    }
    // Well, maybe it's our own stderr and we can parse it?
    let cleaned_up = magical_cleanup(&buf)?;
    serde_json::from_reader::<_, DiceExecutionOrder>(&mut cleaned_up.as_bytes())
        .context(format!("While parsing {}", &cleaned_up))
}

#[derive(clap::Parser)]
#[clap(
    name = "fuzzy-dice",
    about = "a tool for finding bugs in DICE by simulating many different computations"
)]
struct Opts {
    #[clap(subcommand)]
    command: Commands,
}

#[derive(clap::Subcommand)]
enum Commands {
    #[clap(about = "Replays an existing failure.")]
    Replay(SubCommandCommon<Replay>),
    #[clap(about = "Searches for new failures.")]
    Fuzz(SubCommandCommon<Fuzz>),
}

#[derive(Parser)]
struct SubCommandCommon<T: FromArgMatches + Args> {
    #[clap(flatten)]
    cmd: T,
    #[clap(
        long,
        value_parser,
        help = "If set, prints a DICE-dump as JSON to given location after each operation."
    )]
    print_dumps: Option<PathBuf>,
}

#[derive(Parser)]
struct Replay {
    #[clap(
        value_parser,
        help = "the path to the file containing the execution to replay"
    )]
    path: PathBuf,
}

#[derive(Parser)]
struct Fuzz {
    #[clap(
        default_value_t = 2_000_000,
        help = "The maximum number of tests for fuzzing. The actual number may be lower due to\
            discarded test cases"
    )]
    max_tests: u64,
    #[clap(
        default_value_t = 2_000_000,
        help = "The number of passes to hit before stopping and considering it as a pass"
    )]
    num_tests: u64,
}

fn main() -> anyhow::Result<()> {
    struct Fuzzer {
        options: DiceExecutionOrderOptions,
    }

    impl Fuzzer {
        async fn shrink_failure(&self, execution: DiceExecutionOrder) -> Option<TestResult> {
            let mut res = None;
            let mut executions = execution.shrink();

            while let Some(exec) = executions.next() {
                let r_new = qc_fuzz(&exec, &self.options).await;
                if r_new.is_failure() {
                    eprintln!("Found failure at {}... continuing to shrink", exec.uuid);

                    res = Some(r_new);

                    executions = exec.shrink();
                }
            }

            res
        }
    }

    impl Testable for Fuzzer {
        #[tokio::main]
        async fn result(&self, g: &mut Gen) -> TestResult {
            let execution = DiceExecutionOrder::arbitrary(g);
            let r = qc_fuzz(&execution, &self.options).await;

            if r.is_failure() {
                eprintln!(
                    "Found failure at execution {}. Beginning shrinking...",
                    execution.uuid
                );
                self.shrink_failure(execution).await.unwrap_or(r)
            } else {
                r
            }
        }
    }

    struct Replayer {
        execution: DiceExecutionOrder,
        options: DiceExecutionOrderOptions,
    }

    impl Testable for Replayer {
        #[tokio::main]
        async fn result(&self, _: &mut Gen) -> TestResult {
            self.execution.execute(&self.options).await
        }
    }

    async fn qc_fuzz(
        execution: &DiceExecutionOrder,
        options: &DiceExecutionOrderOptions,
    ) -> TestResult {
        if let Some(dump_loc) = execution.get_dump_dir(options) {
            fs::create_dir_all(&dump_loc).unwrap();
            let writer = File::create(dump_loc.join("execution_order"))
                .expect("failed to create execution file");
            serde_json::to_writer_pretty(writer, &execution)
                .expect("failed to serialized execution");
        }
        let res = execution.execute(options).await;

        if !(res.is_error() || res.is_failure()) {
            if let Some(dump_loc) = execution.get_dump_dir(options) {
                // we don't keep dump of anything that are not a failure
                if dump_loc.exists() {
                    fs::remove_dir_all(dump_loc).expect("failed to remove dump");
                }
            }
        }

        res
    }

    let cmd = Opts::parse();

    match cmd.command {
        Commands::Fuzz(fuzz) => {
            let fuzzer = Fuzzer {
                options: DiceExecutionOrderOptions {
                    print_dumps: fuzz.print_dumps,
                },
            };

            QuickCheck::new()
                .max_tests(fuzz.cmd.max_tests)
                .tests(fuzz.cmd.num_tests)
                .gen(Gen::new(10))
                .quickcheck(fuzzer);
        }
        Commands::Replay(replay_cmd) => {
            tracing_subscriber::registry()
                .with(fmt::layer())
                .with(EnvFilter::from_default_env())
                .init();
            let execution = execution_order_from_path(&replay_cmd.cmd.path)?;
            let options = DiceExecutionOrderOptions {
                print_dumps: replay_cmd.print_dumps,
            };

            QuickCheck::new()
                .max_tests(1)
                .quickcheck(Replayer { execution, options });
        }
    }

    println!("Fuzzing complete.");
    Ok(())
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

fn main() {
    println!("Hello World!");
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::process::Command;

// A simple wrapper that execs into rustc
fn main() {
    let args: Vec<_> = std::env::args_os().skip(1).collect();
    let err = Command::new("rustc").args(&args).status().unwrap();
    if !err.success() {
        eprintln!("Error: {}", err);
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

fn main() {
    println!("Hello from Rust!");
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::env::args;
use std::ffi::CString;
use std::os::raw::c_char;

fn main() {
    init_caml();
    println!("fib(10) = {}", format_result(fib(10)))
}

extern "C" {
    pub fn caml_startup(argv: *const *const c_char);
    pub fn caml_named_value(s: *const c_char) -> *const usize;
    pub fn caml_callback(closure: usize, arg: usize) -> usize;
}

fn fib(n: isize) -> isize {
    let fib = CString::new("fib").unwrap();
    let result = unsafe {
        let fib_closure = caml_named_value(fib.as_ptr());
        caml_callback(*fib_closure, isize_to_ocaml(n))
    };
    isize_from_ocaml(result)
}

fn format_result(n: isize) -> String {
    let format_result = CString::new("format_result").unwrap();
    unsafe {
        let format_result_closure = caml_named_value(format_result.as_ptr());
        let result = caml_callback(*format_result_closure, isize_to_ocaml(n)) as *const usize;
        (std::str::from_utf8(bytes_from_ocaml(&result)).unwrap()).to_owned()
    }
}

fn init_caml() {
    let argv: Vec<CString> = (args().into_iter())
        .map(|arg| CString::new(arg.as_str()).unwrap())
        .collect();
    let mut p_argv: Vec<*const c_char> = argv.iter().map(|arg| arg.as_ptr()).collect();
    p_argv.push(std::ptr::null());
    unsafe {
        caml_startup(p_argv.as_ptr());
    }
}

pub fn isize_from_ocaml(n: usize) -> isize {
    (n as isize) >> 1
}

pub fn isize_to_ocaml(n: isize) -> usize {
    (n as usize) << 1 | 1
}

pub fn bytes_from_ocaml<'a>(value: &'a *const usize) -> &'a [u8] {
    unsafe {
        let ptr: *const usize = *value;
        let header = ptr.offset(-1);

        let header_bits = *header;
        let block_size = header_bits >> 10;
        let block_size_in_bytes = block_size * std::mem::size_of::<usize>();

        let ptr = ptr as *const u8;
        let padding = *ptr.add(block_size_in_bytes - 1);
        let len = block_size_in_bytes - padding as usize - 1;

        std::slice::from_raw_parts(ptr, len)
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

#[no_mangle]
pub unsafe extern "C" fn caml_print_hello(_: usize) -> usize {
    println!("Hello Rust!\n");
    return 0;
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

mod print_hello;
fn main() {
    print_hello::print_hello();
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

pub fn print_hello() {
    println!("hello world from rust toolchain");
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::any::Any;
use std::any::TypeId;
use std::marker::PhantomData;

/// A comparable "token" that can be returned to wrap a reference to an [`Any`
/// type](Any) for [`PartialEq`](PartialEq).
///
/// This lets dyn traits be comparable by having all implementations return some
/// "token" that can be considered [`PartialEq`](PartialEq).
pub struct PartialEqAny<'a> {
    type_id: TypeId,
    cmp: unsafe fn(*const (), *const ()) -> bool,
    val: *const (),
    _marker: PhantomData<&'a dyn Any>,
}

impl<'a> PartialEqAny<'a> {
    #[inline]
    pub fn new<A: PartialEq + 'static>(a: &'a A) -> Self {
        PartialEqAny {
            type_id: TypeId::of::<A>(),
            cmp: |this, other| {
                // SAFETY: We only call `cmp` with
                //   `this.type_id == other.type_id == TypeId::of::<A>()`.
                let this = unsafe { &*(this as *const A) };
                let other = unsafe { &*(other as *const A) };
                this == other
            },
            val: a as *const A as *const (),
            _marker: PhantomData,
        }
    }

    /// Get `TypeId` of the referenced type.
    #[inline]
    pub fn type_id(&self) -> TypeId {
        self.type_id
    }

    /// gets an instance that always compares to false
    #[inline]
    pub fn always_false() -> Self {
        struct AlwaysFalse;

        impl PartialEq for AlwaysFalse {
            fn eq(&self, _other: &Self) -> bool {
                false
            }
        }

        PartialEqAny::new(&AlwaysFalse)
    }
}

impl<'a> PartialEq for PartialEqAny<'a> {
    #[inline]
    fn eq(&self, other: &PartialEqAny<'a>) -> bool {
        self.type_id == other.type_id && unsafe { (self.cmp)(self.val, other.val) }
    }
}

#[cfg(test)]
#[allow(clippy::bool_assert_comparison)]
mod tests {
    use crate::eq::PartialEqAny;

    struct Wrap<T>(T);

    impl<T: PartialEq + 'static> Wrap<T> {
        fn token(&self) -> PartialEqAny {
            PartialEqAny::new(&self.0)
        }
    }

    #[test]
    fn test_cmp_any() {
        let w1 = Wrap(1);
        let w2 = Wrap(1);
        let w3 = Wrap(2);

        assert_eq!(w1.token() == w2.token(), true);
        assert_eq!(w1.token() == w3.token(), false);

        let w4 = Wrap("foo");
        let w5 = Wrap("foo");
        let w6 = Wrap("bar");

        assert_eq!(w4.token() == w5.token(), true);
        assert_eq!(w4.token() == w6.token(), false);

        assert_eq!(w1.token() == w6.token(), false);
    }

    #[test]
    #[allow(clippy::eq_op)]
    fn always_false_cmp() {
        let w = Wrap(1);
        let f = PartialEqAny::always_false();

        assert_eq!(f == f, false);
        assert_eq!(f == w.token(), false);
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

mod eq;
mod ord;

pub use eq::PartialEqAny;
pub use ord::OrdAny;


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::any::Any;
use std::any::TypeId;
use std::cmp::Ordering;
use std::marker::PhantomData;

/// Ordering between arbitrary types.
pub struct OrdAny<'a> {
    type_id: TypeId,
    cmp: unsafe fn(*const (), *const ()) -> Ordering,
    val: *const (),
    _marker: PhantomData<&'a dyn Any>,
}

impl<'a> OrdAny<'a> {
    #[inline]
    pub fn new<A: Ord + 'static>(a: &'a A) -> Self {
        OrdAny {
            type_id: TypeId::of::<A>(),
            cmp: |this, other| {
                // SAFETY: We only call `cmp` with
                //   `this.type_id == other.type_id == TypeId::of::<A>()`.
                let this = unsafe { &*(this as *const A) };
                let other = unsafe { &*(other as *const A) };
                this.cmp(other)
            },
            val: a as *const A as *const (),
            _marker: PhantomData,
        }
    }

    /// Get `TypeId` of the referenced type.
    #[inline]
    pub fn type_id(&self) -> TypeId {
        self.type_id
    }
}

impl<'a> PartialEq for OrdAny<'a> {
    #[inline]
    fn eq(&self, other: &OrdAny<'a>) -> bool {
        self.cmp(other) == Ordering::Equal
    }
}

impl<'a> Eq for OrdAny<'a> {}

impl<'a> PartialOrd for OrdAny<'a> {
    #[inline]
    fn partial_cmp(&self, other: &OrdAny<'a>) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

/// Compare by type id first, then by value.
impl<'a> Ord for OrdAny<'a> {
    #[inline]
    fn cmp(&self, other: &Self) -> Ordering {
        let type_cmp = self.type_id.cmp(&other.type_id);
        if type_cmp != Ordering::Equal {
            return type_cmp;
        }
        unsafe { (self.cmp)(self.val, other.val) }
    }
}

#[cfg(test)]
mod tests {
    use std::any::TypeId;
    use std::cmp::Ordering;

    use crate::OrdAny;

    #[test]
    fn test_ord_any() {
        assert!(OrdAny::new(&1) < OrdAny::new(&2));
        assert!(OrdAny::new(&true) > OrdAny::new(&false));
        assert_eq!(
            Ordering::Equal,
            OrdAny::new(&String::new()).cmp(&OrdAny::new(&String::new()))
        );
        assert_eq!(
            OrdAny::new(&1i32) < OrdAny::new(&true),
            TypeId::of::<i32>() < TypeId::of::<bool>()
        );
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! Provides utilities to implement `Display`, which also provides an "alternate" display.
//!
//! As an example of using these combinators:
//!
//! ```
//! use std::fmt;
//! use display_container::*;
//!
//! struct MyItems(Vec<(String, i32)>);
//!
//! impl fmt::Display for MyItems {
//!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
//!         fmt_container(f, "{", "}",
//!             iter_display_chain(
//!                 &["magic"],
//!                 self.0.iter().map(|(k, v)| display_pair(k, "=", v))
//!             )
//!         )
//!     }
//! }
//! ```
//!
//! Would produce results such as:
//!
//! ```ignore
//! {magic, hello=1, world=2}
//! ```
//!
//! For "normal" display, produces output like (with `prefix="prefix[", suffix="]"`):
//!
//! `prefix[]`
//! `prefix[1]`
//! `prefix[1, 2]`
//!
//! For "alternate" display, produces output like:
//!
//! `prefix[]`
//! `prefix[ 1 ]`
//! ```ignore
//! prefix[
//!   1,
//!   2
//! ]
//! ```
//!
//! This doesn't propagate the flags on the Formatter other than alternate.
// TODO(cjhopman): Starlark values don't really do anything with the rest of the flags so
// propagating them hasn't been necessary, but it would be easy enough to implement if we wanted to.

use std::fmt;
use std::fmt::Display;
use std::fmt::Write;

use either::Either;

const INDENT: &str = "  ";

/// Used to indent a displayed item for alternate display. This helps us pretty-print deep data structures.
fn subwriter<T: Display>(indent: &'static str, f: &mut fmt::Formatter, v: T) -> fmt::Result {
    if f.alternate() {
        write!(indenter::indented(f).with_str(indent), "{:#}", &v)
    } else {
        Display::fmt(&v, f)
    }
}

/// Iterator length for display.
enum Len {
    Zero,
    One,
    Many, // > 1
}

/// Display a pair of elements with a separator in the middle.
///
/// Equivalent to `write!(f, "{}{}{}", key, separator, value)`.
pub fn display_pair<'a, K: Display + 'a, V: Display + 'a>(
    key: K,
    separator: &'a str,
    value: V,
) -> impl Display + 'a {
    DisplayPair(key, separator, value)
}

struct DisplayPair<'a, K: Display, V: Display>(pub K, pub &'a str, pub V);

impl<'a, K: Display, V: Display> Display for DisplayPair<'a, K, V> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        Display::fmt(&self.0, f)?;
        f.write_str(self.1)?;
        Display::fmt(&self.2, f)
    }
}

/// The low-level helper for displaying containers. For simple containers, it may be more convenient to use `display_container` or `display_keyed_container`.
struct ContainerDisplayHelper<'a, 'b> {
    f: &'a mut fmt::Formatter<'b>,
    /// The additional separator to be added after each item (except the last).
    separator: &'static str,
    /// Extra output to be added after the prefix and before the suffix. Only non-empty for the single item case.
    outer: &'static str,
    /// The indent used for each item in the multiple items case (where each item is placed on its own line).
    indent: &'static str,
    /// A count of items, used for correctly adding the separator.
    seen_items: usize,
}

impl<'a, 'b> ContainerDisplayHelper<'a, 'b> {
    /// Begins displaying a container. The provided num_items will be used to select which formatting to use for alternate display.
    fn begin_inner(
        f: &'a mut fmt::Formatter<'b>,
        prefix: &str,
        num_items: Len,
    ) -> Result<Self, fmt::Error> {
        let (separator, outer, indent) = match (f.alternate(), num_items) {
            // We want to be formatted as `{prefix}item1, item2{suffix}`, like `[1, 2]` for lists.
            (false, _) => (", ", "", ""),
            // We want to be formatted as `{prefix}{suffix}`, like `[]` for lists.
            (true, Len::Zero) => ("", "", ""),
            // We want to be formatted as `{prefix} item {suffix}`, like `[ item ]` for lists
            (true, Len::One) => ("", " ", ""),
            // We want to be formatted as `{prefix}\n  item1,\n  item2\n{suffix}`, for lists like:
            // ```
            // [
            //    item1,
            //    item2
            // ]
            // ```
            _ => (",\n", "\n", INDENT),
        };
        f.write_str(prefix)?;
        f.write_str(outer)?;

        Ok(Self {
            f,
            separator,
            outer,
            indent,
            seen_items: 0,
        })
    }

    /// Displays an item.
    pub fn item<T: Display>(&mut self, v: T) -> fmt::Result {
        if self.seen_items != 0 {
            self.f.write_str(self.separator)?;
        }
        self.seen_items += 1;
        subwriter(self.indent, self.f, &v)
    }

    /// Ends displaying a container.
    pub fn end(self, suffix: &str) -> fmt::Result {
        self.f.write_str(self.outer)?;
        self.f.write_str(suffix)
    }
}

/// Helper for display implementation of container-y types (like list, tuple).
pub fn fmt_container<T: Display, Iter: IntoIterator<Item = T>>(
    f: &mut fmt::Formatter,
    prefix: &str,
    suffix: &str,
    items: Iter,
) -> fmt::Result {
    let mut items = items.into_iter();
    let helper = match items.next() {
        None => ContainerDisplayHelper::begin_inner(f, prefix, Len::Zero)?,
        Some(first) => match items.next() {
            None => {
                let mut helper = ContainerDisplayHelper::begin_inner(f, prefix, Len::One)?;
                helper.item(first)?;
                helper
            }
            Some(second) => {
                let mut helper = ContainerDisplayHelper::begin_inner(f, prefix, Len::Many)?;
                helper.item(first)?;
                helper.item(second)?;
                for v in items {
                    helper.item(v)?;
                }
                helper
            }
        },
    };
    helper.end(suffix)
}

/// Helper for display implementation of container-y types (like dict, struct).
///
/// Equivalent to [`fmt_container`] where the items have [`display_pair`] applied to them.
pub fn fmt_keyed_container<K: Display, V: Display, Iter: IntoIterator<Item = (K, V)>>(
    f: &mut fmt::Formatter,
    prefix: &str,
    suffix: &str,
    separator: &str,
    items: Iter,
) -> fmt::Result {
    fmt_container(
        f,
        prefix,
        suffix,
        items
            .into_iter()
            .map(|(k, v)| display_pair(k, separator, v)),
    )
}

/// Chain two iterators together that produce `Display` items.
pub fn iter_display_chain<A, B>(first: A, second: B) -> impl Iterator<Item = impl Display>
where
    A: IntoIterator,
    A::Item: Display,
    B: IntoIterator,
    B::Item: Display,
{
    first
        .into_iter()
        .map(Either::Left)
        .chain(second.into_iter().map(Either::Right))
}

#[cfg(test)]
mod tests {
    use std::fmt;

    use super::*;

    #[test]
    fn test_container() {
        struct Wrapped(Vec<u32>);
        impl fmt::Display for Wrapped {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                fmt_container(f, "prefix[", "]", self.0.iter())
            }
        }

        assert_eq!("prefix[]", format!("{:}", Wrapped(vec![])));
        assert_eq!("prefix[1]", format!("{:}", Wrapped(vec![1])));
        assert_eq!("prefix[1, 2]", format!("{:}", Wrapped(vec![1, 2])));
        assert_eq!("prefix[1, 2, 3]", format!("{:}", Wrapped(vec![1, 2, 3])));

        assert_eq!("prefix[]", format!("{:#}", Wrapped(vec![])));
        assert_eq!("prefix[ 1 ]", format!("{:#}", Wrapped(vec![1])));
        assert_eq!(
            "prefix[\n  1,\n  2\n]",
            format!("{:#}", Wrapped(vec![1, 2])),
        );
        assert_eq!(
            "prefix[\n  1,\n  2,\n  3\n]",
            format!("{:#}", Wrapped(vec![1, 2, 3])),
        );
    }

    #[test]
    fn test_keyed_container() {
        struct Wrapped(Vec<(u32, &'static str)>);
        impl fmt::Display for Wrapped {
            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                fmt_keyed_container(
                    f,
                    "prefix[",
                    "]",
                    ": ",
                    // just wrap with `"` to make it clearer in the output
                    self.0.iter().map(|(k, v)| (k, format!("\"{}\"", v))),
                )
            }
        }

        assert_eq!("prefix[]", format!("{:}", Wrapped(vec![])));
        assert_eq!("prefix[1: \"1\"]", format!("{:}", Wrapped(vec![(1, "1")])));
        assert_eq!(
            "prefix[1: \"1\", 2: \"2\"]",
            format!("{:}", Wrapped(vec![(1, "1"), (2, "2")])),
        );
        assert_eq!(
            "prefix[1: \"1\", 2: \"2\", 3: \"3\"]",
            format!("{:}", Wrapped(vec![(1, "1"), (2, "2"), (3, "3")])),
        );

        assert_eq!("prefix[]", format!("{:#}", Wrapped(vec![])));
        assert_eq!(
            "prefix[ 1: \"1\" ]",
            format!("{:#}", Wrapped(vec![(1, "1")]))
        );
        assert_eq!(
            "prefix[\n  1: \"1\",\n  2: \"2\"\n]",
            format!("{:#}", Wrapped(vec![(1, "1"), (2, "2")])),
        );
        assert_eq!(
            "prefix[\n  1: \"1\",\n  2: \"2\",\n  3: \"3\"\n]",
            format!("{:#}", Wrapped(vec![(1, "1"), (2, "2"), (3, "3")])),
        );
    }

    #[test]
    fn test_combinators() {
        struct MyItems(Vec<(String, i32)>);
        impl fmt::Display for MyItems {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt_container(
                    f,
                    "{",
                    "}",
                    iter_display_chain(
                        &["magic"],
                        self.0.iter().map(|(k, v)| display_pair(k, "=", v)),
                    ),
                )
            }
        }
        assert_eq!(
            MyItems(vec![("hello".to_owned(), 1), ("world".to_owned(), 2)]).to_string(),
            "{magic, hello=1, world=2}"
        );
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::iter::Cloned;

use crate::Dupe;

pub trait IterDupedExt: Sized {
    /// Like `duped()`, but only works for types that implement `Dupe`.
    /// Note that the return type is deliberately `Cloned`, as that behaves
    /// the same as a `Duped` would be, but can take advantage of standard library
    /// optimisations.
    ///
    /// ```
    /// use std::rc::Rc;
    /// use dupe::IterDupedExt;
    /// let inputs = vec![Rc::new("Hello"), Rc::new("World")];
    /// let outputs = inputs.iter().duped().collect::<Vec<_>>();
    /// assert_eq!(inputs, outputs);
    /// ```
    /// use gazebo::prelude::*;
    /// use std::cmp::Ordering;
    fn duped(self) -> Cloned<Self>;
}

impl<'a, I, T> IterDupedExt for I
where
    I: Sized,
    I: Iterator<Item = &'a T>,
    T: 'a + Dupe,
{
    fn duped(self) -> Cloned<Self> {
        self.cloned()
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! A cheap version of [`Clone`](Clone).

pub(crate) mod iter;
pub(crate) mod option;

use std::cell::Cell;
use std::num::*;
use std::rc::Rc;
use std::sync::Arc;

pub use dupe_derive::Clone_;
pub use dupe_derive::Copy_;
pub use dupe_derive::Dupe;
pub use dupe_derive::Dupe_;

pub use crate::iter::IterDupedExt;
pub use crate::option::OptionDupedExt;

/// Like [`Clone`](Clone), but should only be available if [`Clone`](Clone) is
/// constant time and zero allocation (e.g. a few [`Arc`](Arc) bumps).
/// The implementation of `dupe` should _always_ call `clone`.
pub trait Dupe: Clone {
    #[inline]
    fn dupe(&self) -> Self {
        self.clone()
    }
}

// Smart pointer/wrapper types
impl<A: ?Sized> Dupe for &A {}
impl<A: ?Sized> Dupe for *const A {}
impl<A: ?Sized> Dupe for *mut A {}
impl<A: ?Sized> Dupe for Arc<A> {}
impl<A: ?Sized> Dupe for std::sync::Weak<A> {}
impl<A: ?Sized> Dupe for Rc<A> {}
impl<A: ?Sized> Dupe for std::rc::Weak<A> {}
impl<A: Copy> Dupe for Cell<A> {}

// Small containers
impl<A: Dupe> Dupe for Option<A> {}
impl<T: Dupe, E: Dupe> Dupe for Result<T, E> {}
impl<A: Dupe> Dupe for std::ops::Bound<A> {}
impl<A: Dupe> Dupe for std::pin::Pin<A> {}
impl<A: Dupe> Dupe for std::ptr::NonNull<A> {}
impl<A: Dupe> Dupe for std::task::Poll<A> {}
impl<A: Dupe> Dupe for (A,) {}
// Not clear if Dupe should be implemented for pairs or not.
// Concern is deeply nested pairs could be exponentially more expensive than their inner dupes.

// Atomic types
impl Dupe for () {}
impl Dupe for bool {}
impl Dupe for char {}
impl Dupe for u8 {}
impl Dupe for u16 {}
impl Dupe for u32 {}
impl Dupe for u64 {}
impl Dupe for u128 {}
impl Dupe for usize {}
impl Dupe for i8 {}
impl Dupe for i16 {}
impl Dupe for i32 {}
impl Dupe for i64 {}
impl Dupe for i128 {}
impl Dupe for isize {}
impl Dupe for f32 {}
impl Dupe for f64 {}
impl Dupe for NonZeroU8 {}
impl Dupe for NonZeroU16 {}
impl Dupe for NonZeroU32 {}
impl Dupe for NonZeroU64 {}
impl Dupe for NonZeroU128 {}
impl Dupe for NonZeroUsize {}
impl Dupe for NonZeroI8 {}
impl Dupe for NonZeroI16 {}
impl Dupe for NonZeroI32 {}
impl Dupe for NonZeroI64 {}
impl Dupe for NonZeroI128 {}
impl Dupe for NonZeroIsize {}

// Other std types that are Copyable
impl Dupe for std::any::TypeId {}
impl Dupe for std::marker::PhantomPinned {}
impl Dupe for std::net::Ipv4Addr {}
impl Dupe for std::net::Ipv6Addr {}
impl Dupe for std::net::SocketAddrV4 {}
impl Dupe for std::net::SocketAddrV6 {}
impl Dupe for std::thread::ThreadId {}
impl Dupe for std::time::Instant {}
impl Dupe for std::time::SystemTime {}
impl Dupe for std::time::Duration {}
impl<T: ?Sized> Dupe for std::marker::PhantomData<T> {}

impl<R> Dupe for fn() -> R {}
impl<A1, R> Dupe for fn(A1) -> R {}
impl<A1, A2, R> Dupe for fn(A1, A2) -> R {}
impl<A1, A2, A3, R> Dupe for fn(A1, A2, A3) -> R {}
impl<A1, A2, A3, A4, R> Dupe for fn(A1, A2, A3, A4) -> R {}
impl<A1, A2, A3, A4, A5, R> Dupe for fn(A1, A2, A3, A4, A5) -> R {}
impl<A1, A2, A3, A4, A5, A6, R> Dupe for fn(A1, A2, A3, A4, A5, A6) -> R {}
impl<A1, A2, A3, A4, A5, A6, A7, R> Dupe for fn(A1, A2, A3, A4, A5, A6, A7) -> R {}
impl<A1, A2, A3, A4, A5, A6, A7, A8, R> Dupe for fn(A1, A2, A3, A4, A5, A6, A7, A8) -> R {}
impl<A1, A2, A3, A4, A5, A6, A7, A8, A9, R> Dupe for fn(A1, A2, A3, A4, A5, A6, A7, A8, A9) -> R {}
impl<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, R> Dupe
    for fn(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10) -> R
{
}
impl<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, R> Dupe
    for fn(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11) -> R
{
}
impl<A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, R> Dupe
    for fn(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12) -> R
{
}
// Rust goes up to 12 arguments for traits, so we follow

#[cfg(test)]
mod tests {
    use super::*;
    #[allow(unused_imports)] // Not actually unused, this makes testing the derive macro work
    use crate as dupe;

    #[test]
    fn test_dupe_generic() {
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct Foo {}
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct FooT<T> {
            foo: T,
        }
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct Faz;

        let x = Foo {};
        assert_eq!(x, Dupe::dupe(&x));

        let x = FooT { foo: 1 };
        assert_eq!(x, Dupe::dupe(&x));

        let x = Faz;
        assert_eq!(x, Dupe::dupe(&x));
    }

    #[test]
    fn test_dupe_() {
        #[derive(Debug, PartialEq, Eq)]
        struct NoClone();
        #[derive(Dupe_, Debug, PartialEq, Eq)]
        struct FooT<T> {
            foo: Arc<T>,
        }

        impl<T> Clone for FooT<T> {
            fn clone(&self) -> Self {
                FooT {
                    foo: self.foo.clone(),
                }
            }
        }

        let x = FooT {
            foo: Arc::new(NoClone()),
        };
        assert_eq!(x, Dupe::dupe(&x));
    }

    #[test]
    fn test_dupe_enum() {
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct Foo();
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct Foo2;
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct Bar(i64, bool, Foo2);
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        struct Baz {
            foo: usize,
        }
        #[derive(Clone, Dupe, Debug, PartialEq, Eq)]
        enum Qux {
            Foo(),
            Foo2,
            Bar(Foo, Bar),
            Baz { foo: Foo, bar: Bar, baz: Baz },
        }

        let x = Qux::Bar(Foo(), Bar(8, true, Foo2));
        assert_eq!(x, Dupe::dupe(&x));
        let x = Qux::Baz {
            foo: Foo(),
            bar: Bar(7, false, Foo2),
            baz: Baz { foo: 9 },
        };
        assert_eq!(x, Dupe::dupe(&x));
        let x = Qux::Foo();
        assert_eq!(x, Dupe::dupe(&x));
        let x = Qux::Foo2;
        assert_eq!(x, Dupe::dupe(&x));
    }

    #[test]
    fn test_dupe_fn()
    where
        fn(usize): Dupe,
        fn(String, Vec<usize>) -> bool: Dupe,
    {
        // Tests are in the where
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use crate::Dupe;

/// Extension traits on [`Option`](Option) where it holds a ref.
pub trait OptionDupedExt {
    type Item;

    /// Like `cloned`, but with a `Dupe` constraint.
    ///
    /// ```
    /// use std::rc::Rc;
    /// use dupe::OptionDupedExt;
    /// let rc = Rc::new("test");
    /// assert_eq!(Some(&rc).duped(), Some(rc));
    /// assert_eq!(None::<&Rc<String>>.duped(), None);
    /// ```
    fn duped(self) -> Option<Self::Item>
    where
        Self::Item: Dupe;
}

impl<'a, T> OptionDupedExt for Option<&'a T> {
    type Item = T;

    fn duped(self) -> Option<T>
    where
        T: Dupe,
    {
        self.map(|x| x.dupe())
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use quote::quote;
use syn::parse_macro_input;
use syn::DeriveInput;

use crate::util::duplicate_impl;

pub fn derive_clone_(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let name = &input.ident;
    let body = duplicate_impl(&input.data, &quote! { ::std::clone::Clone::clone });
    let gen = quote! {
        impl #impl_generics ::std::clone::Clone for #name #ty_generics #where_clause {
            fn clone(&self) -> Self {
                #body
            }
        }
    };
    gen.into()
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use quote::quote;
use syn::parse_macro_input;
use syn::DeriveInput;

pub fn derive_copy_(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();

    let name = &input.ident;
    let gen = quote! {
        impl #impl_generics ::std::marker::Copy for #name #ty_generics #where_clause {
        }
    };
    gen.into()
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use quote::quote;
use syn::parse_macro_input;
use syn::parse_quote;
use syn::DeriveInput;
use syn::Ident;
use syn::TypeParamBound;

use crate::util::add_trait_bounds;
use crate::util::check_each_field_impls;
use crate::util::extract_all_field_tys;

pub fn derive_dupe(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    derive_dupe_explicit(input, true)
}

pub fn derive_dupe_(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    derive_dupe_explicit(input, false)
}

fn derive_dupe_explicit(
    input: proc_macro::TokenStream,
    with_traits: bool,
) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as DeriveInput);

    let name = &input.ident;

    // Add a bound `T: Dupe` to every type parameter T.
    let generics = if with_traits {
        let bound: TypeParamBound = parse_quote!(dupe::Dupe);
        add_trait_bounds(input.generics, &bound)
    } else {
        input.generics
    };
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    let all_fields = match extract_all_field_tys(&input.data) {
        Ok(r) => r,
        Err(e) => {
            return e.into_compile_error().into();
        }
    };
    let check_each_field_dupe = check_each_field_impls(all_fields, parse_quote!(dupe::Dupe));

    let check_func_name = Ident::new(
        &format!("__implicit_dupe_check_for_fields_of_{}", name),
        name.span(),
    );

    let gen = quote! {
        impl #impl_generics dupe::Dupe for #name #ty_generics #where_clause {
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        fn #check_func_name #impl_generics (_x: #name #ty_generics) #where_clause {
            #check_each_field_dupe
        }
    };

    gen.into()
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

mod clone;
mod copy;
mod dupe;
mod util;

/// Derive the `Dupe` trait.
#[proc_macro_derive(Dupe)]
pub fn derive_dupe(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    dupe::derive_dupe(input)
}

/// Derive the `Dupe` trait, but without requiring all type arguments to implement `Dupe`.
#[proc_macro_derive(Dupe_)]
pub fn derive_dupe_(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    dupe::derive_dupe_(input)
}

/// Derive the [`Clone` trait](Clone), but without requiring all type arguments to implement [`Clone`](Clone).
#[proc_macro_derive(Clone_)]
pub fn derive_clone_(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    clone::derive_clone_(input)
}

/// Derive the [`Copy` trait](Copy), but without requiring all type arguments to implement [`Copy`](Copy).
#[proc_macro_derive(Copy_)]
pub fn derive_copy_(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    copy::derive_copy_(input)
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

use std::iter;

use proc_macro2::TokenStream;
use quote::quote;
use quote::quote_spanned;
use syn::spanned::Spanned;
use syn::Data;
use syn::DataEnum;
use syn::DataStruct;
use syn::Fields;
use syn::GenericParam;
use syn::Generics;
use syn::Ident;
use syn::Index;
use syn::Type;
use syn::TypeParamBound;
use syn::Variant;

// Add a bound to every type parameter.
pub(crate) fn add_trait_bounds(mut generics: Generics, bound: &TypeParamBound) -> Generics {
    for param in &mut generics.params {
        if let GenericParam::Type(ref mut type_param) = *param {
            type_param.bounds.push(bound.clone());
        }
    }
    generics
}

fn duplicate_struct(data: &DataStruct, duplicate: &TokenStream) -> TokenStream {
    match data.fields {
        Fields::Named(ref fields) => {
            // Self {x: clone(self.x), y: clone(self.y)}
            let xs = fields.named.iter().map(|f| {
                let name = &f.ident;
                quote_spanned! {f.span() =>
                    #name: #duplicate(&self.#name)
                }
            });
            quote! {
                Self { #(#xs, )* }
            }
        }
        Fields::Unnamed(ref fields) => {
            // Self(clone(self.0), clone(self.1))
            let xs = fields.unnamed.iter().enumerate().map(|(i, f)| {
                let index = Index::from(i);
                quote_spanned! {f.span()=>
                    #duplicate(&self.#index)
                }
            });
            quote! {
                Self ( #(#xs, )* )
            }
        }
        Fields::Unit => {
            // Self
            quote!(Self)
        }
    }
}

fn duplicate_variant(data: &Variant, duplicate: &TokenStream) -> TokenStream {
    let ctor = &data.ident;
    match data.fields {
        Fields::Named(ref fields) => {
            // Self::Ctor{x,y} => {x: clone(x), y: clone(y)}
            let (pats, es): (Vec<_>, Vec<_>) = fields
                .named
                .iter()
                .map(|f| {
                    let name = &f.ident;
                    (
                        quote_spanned! {f.span() =>
                            #name
                        },
                        quote_spanned! {f.span() =>
                            #name: #duplicate(#name)
                        },
                    )
                })
                .unzip();
            quote! {
                Self::#ctor{ #(#pats, )* } => Self::#ctor{ #(#es, )* }
            }
        }
        Fields::Unnamed(ref fields) => {
            // Self::Ctor(v0,v1) => Self::Ctor(clone(v0), clone(v1))
            let (pats, es): (Vec<_>, Vec<_>) = fields
                .unnamed
                .iter()
                .enumerate()
                .map(|(i, f)| {
                    let var = Ident::new(&format!("v{}", i), f.span());
                    (
                        quote_spanned! {f.span() => #var},
                        quote_spanned! {f.span() => #duplicate(#var)},
                    )
                })
                .unzip();
            quote! {
                Self::#ctor( #(#pats,)* ) => Self::#ctor( #(#es,)* )
            }
        }
        Fields::Unit => {
            // Self::Ctor => Self::Ctor
            quote!(Self::#ctor => Self::#ctor)
        }
    }
}

fn duplicate_enum(data: &DataEnum, duplicate: &TokenStream) -> TokenStream {
    let xs = data
        .variants
        .iter()
        .map(|v| duplicate_variant(v, duplicate));
    quote! {
        match self {
            #(#xs, )*
        }
    }
}

pub(crate) fn duplicate_impl(data: &Data, duplicate: &TokenStream) -> TokenStream {
    match data {
        Data::Struct(data) => duplicate_struct(data, duplicate),
        Data::Enum(data) => duplicate_enum(data, duplicate),
        Data::Union(x) => {
            syn::Error::new_spanned(x.union_token, "Can't derive duplication for unions")
                .into_compile_error()
        }
    }
}

pub(crate) fn extract_all_field_tys<'a>(
    data: &'a Data,
) -> Result<Box<dyn Iterator<Item = &'a Type> + 'a>, syn::Error> {
    match data {
        Data::Struct(data) => Ok(extract_all_field_tys_struct(data)),
        Data::Enum(data) => Ok(extract_all_field_tys_enum(data)),
        Data::Union(x) => Err(syn::Error::new_spanned(
            x.union_token,
            "Can't derive duplication for unions",
        )),
    }
}

fn extract_all_field_tys_struct<'a>(
    data: &'a DataStruct,
) -> Box<dyn Iterator<Item = &'a Type> + 'a> {
    match data.fields {
        Fields::Named(ref fields) => Box::new(fields.named.iter().map(|f| &f.ty)),
        Fields::Unnamed(ref fields) => Box::new(fields.unnamed.iter().map(|f| &f.ty)),
        Fields::Unit => Box::new(iter::empty()),
    }
}

fn extract_all_field_tys_variant<'a>(data: &'a Variant) -> Box<dyn Iterator<Item = &'a Type> + 'a> {
    match data.fields {
        Fields::Named(ref fields) => Box::new(fields.named.iter().map(|f| &f.ty)),
        Fields::Unnamed(ref fields) => Box::new(fields.unnamed.iter().map(|f| &f.ty)),
        Fields::Unit => Box::new(iter::empty()),
    }
}

fn extract_all_field_tys_enum<'a>(data: &'a DataEnum) -> Box<dyn Iterator<Item = &'a Type> + 'a> {
    Box::new(data.variants.iter().flat_map(extract_all_field_tys_variant))
}

pub(crate) fn check_each_field_impls<'a>(
    iter: impl IntoIterator<Item = &'a Type>,
    trait_required: Type,
) -> TokenStream {
    let checks = iter.into_iter().map(|ty| {
        quote! {
                assert_impl_all::<#ty>();
        }
    });

    quote! {
        fn assert_impl_all<T: ?Sized + #trait_required>() {}

        #(#checks)*
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! Cast between types with no conversion.
//!
//! Most of these operations are inherently unsafe, but provided as strongly-typed wrappers
//! to reduce the chance of typos ending up with even more unsafe functions. If you use the
//! result in incorrect ways, it will cause undefined behaviour.

// These are inherently unsafe in fairly obvious ways. Safety is left entirely to the user.
// So doc's wouldn't really help.
#![allow(clippy::missing_safety_doc)]

use std::mem;
use std::ptr;

#[inline(always)]
pub fn ptr_to_usize<T: ?Sized>(x: &T) -> usize {
    x as *const T as *const () as usize
}

/// Undefined behaviour if the argument is zero, or does not satisfy the alignment
/// of type `T`.
#[inline(always)]
pub unsafe fn usize_to_ptr<'a, T>(x: usize) -> &'a T {
    &*(x as *const T)
}

/// Undefined behaviour if the argument does not satisfy the alignment of type `To`.
#[inline(always)]
pub unsafe fn ptr<From, To>(x: &From) -> &To {
    &*(x as *const From as *const To)
}

/// Undefined behaviour if the argument does not satisfy the alignment of type `To`.
#[inline(always)]
pub unsafe fn ptr_mut<From, To>(x: &mut From) -> &mut To {
    &mut *(x as *mut From as *mut To)
}

#[inline(always)]
pub unsafe fn ptr_lifetime<'a, 'b, T: ?Sized>(x: &'a T) -> &'b T {
    &*(x as *const T)
}

/// Like normal [`transmute`](std::mem::transmute), but without the compile-time
/// check that the sizes of the input and output are the same. Despite the removal
/// of the compile-time check, this property _must still hold_, and there is
/// a [`debug_assert_eq`] which checks that. All the rules and warnings from
/// `transmute` still apply.
///
/// This function is mostly useful when you have types that are polymorphic,
/// e.g. `Vec<T>`, that `transmute` cannot be applied to.
#[inline]
pub unsafe fn transmute_unchecked<A, B>(x: A) -> B {
    assert_eq!(mem::size_of::<A>(), mem::size_of::<B>());
    debug_assert_eq!(0, (&x as *const A).align_offset(mem::align_of::<B>()));
    let b = ptr::read(&x as *const A as *const B);
    mem::forget(x);
    b
}

#[macro_export]
/// `transmute!(from-type, to-type, value)` will do a [`transmute`](std::mem::transmute),
/// but the original and result types must be specified.
macro_rules! transmute {
    ($from:ty, $to:ty, $e:expr) => {
        std::mem::transmute::<$from, $to>($e)
    };
}

#[cfg(test)]
mod tests {
    use std::cell::Cell;

    use super::*;

    #[test]
    fn test_transmute() {
        #[allow(clippy::useless_transmute)]
        unsafe fn downcast_string<'a>(x: &'a str) -> &'static str {
            transmute!(&'a str, &'static str, x)
        }
        assert_eq!(unsafe { downcast_string("test") }, "test");
    }

    struct Foo<'a, T>(&'a Cell<isize>, &'a T);

    impl<T> Drop for Foo<'_, T> {
        fn drop(&mut self) {
            self.0.set(self.0.get() - 1)
        }
    }

    #[test]
    fn test_transmute_unchecked() {
        fn magic<'a, T>(x: T) -> Foo<'a, Vec<u8>> {
            unsafe { transmute_unchecked(x) }
        }

        let s = "magic".to_owned();
        let c = Cell::new(8);
        let input = Foo(&c, &s);
        let output = magic(input);
        assert_eq!(c.get(), 8);
        assert_eq!(output.1, b"magic");
        mem::drop(output);
        assert_eq!(c.get(), 7);
    }

    #[test]
    fn test_transmute_unchecked_bytes() {
        fn to_bytes<T>(x: T) -> [u8; 8] {
            unsafe { transmute_unchecked(x) }
        }

        fn from_bytes<T>(x: [u8; 8]) -> T {
            unsafe { transmute_unchecked(x) }
        }

        let x: u64 = 8932489732;
        let y: u64 = from_bytes(to_bytes(x));
        assert_eq!(x, y)
    }

    #[test]
    #[cfg(debug_assertions)]
    #[should_panic]
    fn test_transmute_wrong_sizes() {
        let _: u64 = unsafe { transmute_unchecked(89u32) };
    }

    #[test]
    #[cfg(debug_assertions)]
    #[should_panic]
    fn test_transmute_wrong_alignment() {
        let xs: [u8; 8] = unsafe { transmute_unchecked(0u64) };
        let _: u32 = unsafe { transmute_unchecked(&xs[1..5]) };
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! Additions to the [`Ref`](Ref) mechanism.

// We used to implement `ARef` as an enum of `{Ptr(&'a T), Ref(Ref<'a, T>)}`.
// That works, but consumes 3 words and requires a branch on every access of the underlying
// pointer. We can optimise that by relying on the underlying details of `Ref`, which is
// (currently) defined as (after a bit of inlining):
//
// ```
// pub struct Ref<'a, T: ?Sized + 'a> {
//    value: &'a T,
//    borrow: &'a Cell<isize>,
// }
// ```
//
// Because the pointer must always be non-null, we can switch that out for:
//
// ```
// pub struct ARef<'a, T: ?Sized + 'a> {
//    value: &'a T,
//    borrow: Option<&'a Cell<isize>>,
// }
// ```
//
// And use `None` to represent the `Ptr` case. We do that with transmute trickery,
// but write some good tests that will break if the representation changes,
// and if necessary we can always switch to the enum representation.

use std::cell::BorrowError;
use std::cell::Ref;
use std::cell::RefCell;
use std::cmp::Ordering;
use std::fmt;
use std::fmt::Display;
use std::hash::Hash;
use std::hash::Hasher;
use std::ops::Deref;

#[derive(Debug)]
enum ARefImpl<'a, T: ?Sized + 'a> {
    Ptr(&'a T),
    Ref(Ref<'a, T>),
}

/// A [`Ref`](Ref) that might not actually be borrowed.
/// Either a `Ptr` (a normal & style reference), or a `Ref` (like from
/// [`RefCell`](std::cell::RefCell)), but exposes all the methods available on [`Ref`](Ref).
#[derive(Debug)]
pub struct ARef<'a, T: ?Sized + 'a>(ARefImpl<'a, T>);

impl<T: ?Sized> Deref for ARef<'_, T> {
    type Target = T;

    fn deref(&self) -> &T {
        match &self.0 {
            ARefImpl::Ptr(p) => p,
            ARefImpl::Ref(r) => r.deref(),
        }
    }
}

impl<'a, T: ?Sized + 'a> ARef<'a, T> {
    /// Create a new [`ARef`] from a pointer.
    pub fn new_ptr(x: &'a T) -> Self {
        ARef(ARefImpl::Ptr(x))
    }

    /// Create a new [`ARef`] from a reference.
    pub fn new_ref(x: Ref<'a, T>) -> Self {
        ARef(ARefImpl::Ref(x))
    }

    /// See [`Ref.clone`](Ref::clone). Not a self method since that interferes with the [`Deref`](Deref).
    #[allow(clippy::should_implement_trait)]
    pub fn clone(orig: &Self) -> Self {
        match &orig.0 {
            ARefImpl::Ptr(p) => ARef(ARefImpl::Ptr(p)),
            ARefImpl::Ref(r) => ARef(ARefImpl::Ref(Ref::clone(r))),
        }
    }

    /// See [`Ref.map`](Ref::map). Not a self method since that interferes with the [`Deref`](Deref).
    pub fn map<U: ?Sized, F>(orig: ARef<'a, T>, f: F) -> ARef<'a, U>
    where
        F: FnOnce(&T) -> &U,
    {
        match orig.0 {
            ARefImpl::Ptr(p) => ARef(ARefImpl::Ptr(f(p))),
            ARefImpl::Ref(r) => ARef(ARefImpl::Ref(Ref::map(r, f))),
        }
    }

    /// See [`Ref.map_split`](Ref::map_split). Not a self method since that interferes with the
    /// [`Deref`](Deref).
    pub fn map_split<U: ?Sized, V: ?Sized, F>(orig: ARef<'a, T>, f: F) -> (ARef<'a, U>, ARef<'a, V>)
    where
        F: FnOnce(&T) -> (&U, &V),
    {
        match orig.0 {
            ARefImpl::Ptr(p) => {
                let (u, v) = f(p);
                (ARef(ARefImpl::Ptr(u)), ARef(ARefImpl::Ptr(v)))
            }
            ARefImpl::Ref(r) => {
                let (u, v) = Ref::map_split(r, f);
                (ARef(ARefImpl::Ref(u)), ARef(ARefImpl::Ref(v)))
            }
        }
    }

    /// See [`Ref.filter_map`](Ref::filter_map). Not a self method since that interferes with the
    /// [`Deref`](Deref).
    pub fn filter_map<U: ?Sized, F>(orig: ARef<'a, T>, f: F) -> Result<ARef<'a, U>, Self>
    where
        F: FnOnce(&T) -> Option<&U>,
    {
        match orig.0 {
            ARefImpl::Ptr(p) => match f(p) {
                Some(u) => Ok(ARef(ARefImpl::Ptr(u))),
                None => Err(ARef(ARefImpl::Ptr(p))),
            },
            ARefImpl::Ref(r) => match Ref::filter_map(r, f) {
                Ok(u) => Ok(ARef(ARefImpl::Ref(u))),
                Err(r) => Err(ARef(ARefImpl::Ref(r))),
            },
        }
    }
}

// `Ref` doesn't have many traits on it. I don't really know why - I think that's an oversight.
// & references do have many traits on them. Therefore, when being "either" we choose to do as many
// implementations as we can.

impl<T: Display + ?Sized> Display for ARef<'_, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        ARef::deref(self).fmt(f)
    }
}

impl<T: Hash + ?Sized> Hash for ARef<'_, T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        ARef::deref(self).hash(state)
    }
}

impl<A: PartialEq<B> + ?Sized, B: ?Sized> PartialEq<ARef<'_, B>> for ARef<'_, A> {
    fn eq(&self, other: &ARef<'_, B>) -> bool {
        ARef::deref(self).eq(ARef::deref(other))
    }
}

impl<A: Eq + ?Sized> Eq for ARef<'_, A> {}

impl<A: PartialOrd<B> + ?Sized, B: ?Sized> PartialOrd<ARef<'_, B>> for ARef<'_, A> {
    fn partial_cmp(&self, other: &ARef<'_, B>) -> Option<Ordering> {
        ARef::deref(self).partial_cmp(ARef::deref(other))
    }
}

impl<A: Ord + ?Sized> Ord for ARef<'_, A> {
    fn cmp(&self, other: &Self) -> Ordering {
        ARef::deref(self).cmp(ARef::deref(other))
    }
}

/// Obtain an [`ARef`] from either a normal pointer or a [`RefCell`](std::cell::RefCell).
pub trait AsARef<T: ?Sized> {
    /// Get an [`ARef`] pointing at this type.
    fn as_aref(this: &Self) -> ARef<T>;
    /// Try and get an [`ARef`] pointing at this type. Returns an [`Err`] if
    /// the type `Self` is a [`RefCell`] which is already mutably borrowed.
    fn try_as_aref(this: &Self) -> Result<ARef<T>, BorrowError>;
    /// Return the underlying [`RefCell`] if `Self` is one, otherwise [`None`].
    fn as_ref_cell(this: &Self) -> Option<&RefCell<T>>;
}

impl<T: ?Sized> AsARef<T> for T {
    fn as_aref(this: &Self) -> ARef<T> {
        ARef::new_ptr(this)
    }
    fn try_as_aref(this: &Self) -> Result<ARef<T>, BorrowError> {
        Ok(ARef::new_ptr(this))
    }
    fn as_ref_cell(_this: &Self) -> Option<&RefCell<T>> {
        None
    }
}

impl<T: ?Sized> AsARef<T> for RefCell<T> {
    fn as_aref(this: &Self) -> ARef<T> {
        ARef::new_ref(this.borrow())
    }
    fn try_as_aref(this: &Self) -> Result<ARef<T>, BorrowError> {
        Ok(ARef::new_ref(this.try_borrow()?))
    }
    fn as_ref_cell(this: &Self) -> Option<&RefCell<T>> {
        Some(this)
    }
}

#[cfg(test)]
mod tests {
    use std::cell::RefCell;
    use std::mem;

    use super::*;
    use crate::cast;

    #[test]
    fn test_from_ref_docs() {
        let c = RefCell::new((5, 'b'));
        let b1: ARef<(u32, char)> = ARef::new_ref(c.borrow());
        let b2: ARef<u32> = ARef::map(b1, |t| &t.0);
        assert_eq!(*b2, 5);

        let cell = RefCell::new([1, 2, 3, 4]);
        let borrow = ARef::new_ref(cell.borrow());
        let (begin, end) = ARef::map_split(borrow, |slice| slice.split_at(2));
        assert_eq!(*begin, [1, 2]);
        assert_eq!(*end, [3, 4]);
    }

    #[test]
    fn test_borrow_guards() {
        let c = RefCell::new(5);
        assert!(c.try_borrow_mut().is_ok());
        let r1 = ARef::new_ref(c.borrow());
        assert!(c.try_borrow_mut().is_err());
        let r2 = c.borrow();
        assert!(c.try_borrow_mut().is_err());
        mem::drop(r1);
        assert!(c.try_borrow_mut().is_err());
        mem::drop(r2);
        assert!(c.try_borrow_mut().is_ok());
    }

    #[test]
    fn test_pointer_basics() {
        let c = "test".to_owned();
        let p = ARef::new_ptr(&c);
        let p2 = ARef::map(p, |x| &x[1..3]);
        assert_eq!(&*p2, "es");
    }

    #[test]
    fn test_ref_map_dropping() {
        let c = RefCell::new("test".to_owned());
        let p = ARef::new_ref(c.borrow());
        let p = ARef::map(p, |x| &x[1..3]);
        assert_eq!(&*p, "es");
        mem::drop(p);
        assert!(c.try_borrow_mut().is_ok());
    }

    #[test]
    fn test_ref_filter_map_dropping() {
        let c = RefCell::new("test".to_owned());
        let p = ARef::new_ref(c.borrow());
        let p = ARef::filter_map(p, |x| Some(&x[1..3])).unwrap();
        assert_eq!(&*p, "es");
        mem::drop(p);
        assert!(c.try_borrow_mut().is_ok());
    }

    #[test]
    /// Test that the representation of ARef is what we expect
    fn test_ref_as_expected() {
        let orig = RefCell::new("test".to_owned());
        let p = orig.borrow();
        let p2 = Ref::clone(&p);
        let (pointer, cell): (usize, usize) = unsafe { mem::transmute(p) };
        // We expect the first to be a pointer to the underlying string
        assert_eq!(pointer, cast::ptr_to_usize(Ref::deref(&p2)));
        // We want to make sure the second is never zero
        assert_ne!(cell, 0);

        // Put it back as it was, to make sure our test doesn't leak memory
        let _ignore: Ref<String> = unsafe { mem::transmute((pointer, cell)) };
    }

    #[test]
    fn test_as_aref() {
        fn get_str(x: &impl AsARef<String>) -> ARef<str> {
            ARef::map(AsARef::as_aref(x), |x| x.as_str())
        }

        let a = RefCell::new("hello".to_owned());
        let b = "world".to_owned();
        assert_eq!(&*get_str(&a), "hello");
        assert_eq!(&*get_str(&b), "world");
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! Traits to help implementing dynamic comparisons.

/// Performs a chain of comparison operation expressions yielding `std::cmp::Ordering`, supporting
/// early exit upon hitting the first expressions that doesn't yield `std::cmp::Ordering::Equal`
/// and returning the result of that. This is useful for easily writing a sequence of expressions
/// necessary to yield a comparison result.
/// The macro is expanded inplace, so any expressions dealing with `Result` types are allowed
/// provided that the larger scope allows returning result.
///
/// ```
/// use std::cmp::Ordering;
/// use gazebo::cmp_chain;
///
/// assert_eq!(
///     cmp_chain! {
///         1.cmp(&1),
///         Ok::<_, ()>(2.cmp(&2))?,
///         3.cmp(&4),
///         panic!("won't reach this"),
///     },
///     Ordering::Less,
/// );
///
/// # Ok::<_, ()>(())
/// ```
#[macro_export]
macro_rules! cmp_chain {
    ($e:expr) => {
        $e
    };
    ($e:expr, $($x:expr),+ $(,)?) => {
        match $e {
            std::cmp::Ordering::Equal => {
                cmp_chain!($($x),+)
            },
            c => {
                c
            }
        }
    };
}

/// Performs a chain of equals operation expressions yielding `bool`, supporting
/// early exit upon hitting the first expressions that returns `false` and returning `false`.
/// This is useful for easily writing a sequence of equals expressions necessary to yield a `bool`
/// The macro is expanded inplace, so any expressions dealing with `Result` types are allowed
/// provided that the larger scope allows returning result.
///
/// ```
/// use gazebo::eq_chain;
///
/// assert_eq!(
///     eq_chain! {
///         1 == 1,
///         Ok::<_, ()>(2 == 2)?,
///         3 == 4,
///         panic!("won't reach this"),
///     },
///     false,
/// );
///
/// # Ok::<_, ()>(())
/// ```
#[macro_export]
macro_rules! eq_chain {
    ($e:expr) => {
        $e
    };
    ($e:expr, $($x:expr),+ $(,)?) => {
        if $e {
            eq_chain!($($x),+)
        } else {
            false
        }
    };
}

#[cfg(test)]
mod tests {
    use std::cmp::Ordering;

    #[test]
    fn cmp_eq_chain() {
        struct FakeComparable(
            Box<dyn Fn() -> Ordering>,
            Box<dyn Fn() -> Ordering>,
            Box<dyn Fn() -> Ordering>,
        );
        impl PartialEq for FakeComparable {
            fn eq(&self, _other: &Self) -> bool {
                eq_chain!(
                    (self.0)() == Ordering::Equal,
                    (self.1)() == Ordering::Equal,
                    (self.2)() == Ordering::Equal,
                )
            }
        }
        impl Eq for FakeComparable {}
        impl PartialOrd for FakeComparable {
            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
                Some(self.cmp(other))
            }
        }
        impl Ord for FakeComparable {
            fn cmp(&self, _other: &Self) -> Ordering {
                cmp_chain! {
                    (self.0)(),
                    (self.1)(),
                    (self.2)(),
                }
            }
        }

        let fake = FakeComparable(
            Box::new(|| Ordering::Less),
            Box::new(|| unreachable!("should return less")),
            Box::new(|| unreachable!("should return less")),
        );
        assert_eq!(fake.cmp(&fake), Ordering::Less);
        assert_eq!(fake.eq(&fake), false);

        let fake = FakeComparable(
            Box::new(|| Ordering::Greater),
            Box::new(|| unreachable!("should return less")),
            Box::new(|| unreachable!("should return less")),
        );
        assert_eq!(fake.cmp(&fake), Ordering::Greater);
        assert_eq!(fake.eq(&fake), false);

        let fake = FakeComparable(
            Box::new(|| Ordering::Equal),
            Box::new(|| Ordering::Less),
            Box::new(|| unreachable!("should return less")),
        );
        assert_eq!(fake.cmp(&fake), Ordering::Less);
        assert_eq!(fake.eq(&fake), false);

        let fake = FakeComparable(
            Box::new(|| Ordering::Equal),
            Box::new(|| Ordering::Equal),
            Box::new(|| Ordering::Greater),
        );
        assert_eq!(fake.cmp(&fake), Ordering::Greater);
        assert_eq!(fake.eq(&fake), false);

        let fake = FakeComparable(
            Box::new(|| Ordering::Equal),
            Box::new(|| Ordering::Equal),
            Box::new(|| Ordering::Equal),
        );
        assert_eq!(fake.cmp(&fake), Ordering::Equal);
        assert_eq!(fake.eq(&fake), true);
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! File/IO operations.

use std::fs::create_dir_all;
use std::fs::write;
use std::io;
use std::path::Path;

/// A simple api for creating all the directories up to a path for a file, and
/// then writing the contents to that file.
pub fn create_dirs_and_write<P: AsRef<Path>, C: AsRef<[u8]>>(
    path: P,
    contents: C,
) -> io::Result<()> {
    // no parent means no directory component, and we can directly write to that
    // file
    path.as_ref().parent().map_or(Ok(()), create_dir_all)?;

    write(path.as_ref(), contents)
}

#[cfg(test)]
mod tests {
    use std::fs;
    use std::path::PathBuf;
    use std::time::SystemTime;

    use super::*;

    // We'd rather use something like tempdir, but keep the dependencies down
    struct RemoveDir(PathBuf);

    impl Drop for RemoveDir {
        fn drop(&mut self) {
            // Delete the path, ignore errors
            let _ignore = fs::remove_dir_all(&self.0);
        }
    }

    fn random_part() -> String {
        match SystemTime::now().duration_since(SystemTime::UNIX_EPOCH) {
            Ok(x) => x.as_nanos().to_string(),
            Err(_) => "no_random_part".to_owned(),
        }
    }

    #[test]
    fn test_create_all_and_write() -> io::Result<()> {
        // Make sure we create the directory with unique entropy in it (so no clashes)
        // and clean up after ourselves (so we don't leak files)
        let temp = std::env::temp_dir();
        let temp = temp.join("gazebo");
        let temp = temp.join(random_part());
        // We don't delete $TMP/gazebo because someone else might be using that
        let remove_dir = RemoveDir(temp.clone());

        let temp = temp.join("foo/bar");
        create_dirs_and_write(&temp, "contents")?;
        let contents = fs::read_to_string(temp)?;
        assert_eq!(contents, "contents");

        drop(remove_dir);
        Ok(())
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

//! Utilities for working with hashes.

use std::cmp;
use std::collections::hash_map::DefaultHasher;
use std::fmt;
use std::fmt::Display;
use std::hash::Hash;
use std::hash::Hasher;

use dupe::Dupe;

/// A type `T`, but with the hash computed in advance, so hashing is O(1).
#[derive(Dupe, Clone, Copy, PartialEq, Eq, Debug)]
pub struct Hashed<T> {
    hash: u64,
    value: T,
}

#[allow(clippy::derived_hash_with_manual_eq)]
impl<T> Hash for Hashed<T> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.hash.hash(state)
    }
}

impl<T: Display> Display for Hashed<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.value.fmt(f)
    }
}

impl<T: PartialOrd> PartialOrd for Hashed<T> {
    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
        self.value.partial_cmp(&other.value)
    }
}

impl<T: Ord> Ord for Hashed<T> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        self.value.cmp(&other.value)
    }
}

impl<T> AsRef<T> for Hashed<T> {
    fn as_ref(&self) -> &T {
        &self.value
    }
}

impl<T> AsMut<T> for Hashed<T> {
    fn as_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T: Hash> From<T> for Hashed<T> {
    fn from(value: T) -> Self {
        Self::new(value)
    }
}

impl<T: Hash> Hashed<T> {
    pub fn new(value: T) -> Self {
        let mut hasher = DefaultHasher::new();
        value.hash(&mut hasher);
        Self {
            hash: hasher.finish(),
            value,
        }
    }

    pub fn into(self) -> T {
        self.value
    }
}

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

    #[test]
    fn test_hashed() {
        let v1 = Hashed::new("test");
        let v2 = Hashed::from("test");
        let v3 = Hashed::new("magic");
        assert_eq!(v1, v2);
        assert_ne!(v1, v3);
    }
}


/*
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under both the MIT license found in the
 * LICENSE-MIT file in the root directory of this source tree and the Apache
 * License, Version 2.0 found in the LICENSE-APACHE file in the root directory
 * of this source tree.
 */

#![cfg_attr(feature = "str_pattern_extensions", feature(pattern))]
#![cfg_attr(feature = "str_pattern_extensions", feature(associated_type_bounds))]

//! A collection of well-tested primitives that have been useful. Most modules stand alone.

pub mod cast;
pub mod cell;
pub mod cmp;
pub(crate) mod ext;
pub mod file;
pub mod hash;
pub mod phantom;
pub mod prelude;
pub mod types;
pub mod variants;

#[cfg(test)]
mod test;