text:
use crate::{
    config, id,
    stake_state::{StakeAccount, StakeState},
};
use bincode::deserialize;
use log::*;
use serde_derive::{Deserialize, Serialize};
use solana_sdk::{
    account::KeyedAccount,
    clock::Slot,
    instruction::{AccountMeta, Instruction, InstructionError},
    pubkey::Pubkey,
    system_instruction, sysvar,
};

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum StakeInstruction {
    /// `Lockup` a stake until the specified slot
    ///
    /// Expects 1 Account:
    ///    0 - Uninitialized StakeAccount to be lockup'd
    ///
    /// The u64 is the portion of the Stake account balance to be activated,
    ///    must be less than StakeAccount.lamports
    ///
    Lockup(Slot),

    /// `Delegate` a stake to a particular node
    ///
    /// Expects 3 Accounts:
    ///    0 - Lockup'd StakeAccount to be delegated <= must have this signature
    ///    1 - VoteAccount to which this Stake will be delegated
    ///    2 - Clock sysvar Account that carries clock bank epoch
    ///    3 - Config Account that carries stake config
    ///
    /// The u64 is the portion of the Stake account balance to be activated,
    ///    must be less than StakeAccount.lamports
    ///
    DelegateStake(u64),

    /// Redeem credits in the stake account
    ///
    /// Expects 4 Accounts:
    ///    0 - Delegate StakeAccount to be updated with rewards
    ///    1 - VoteAccount to which the Stake is delegated,
    ///    2 - RewardsPool Stake Account from which to redeem credits
    ///    3 - Rewards sysvar Account that carries points values
    ///    4 - StakeHistory sysvar that carries stake warmup/cooldown history
    RedeemVoteCredits,

    /// Withdraw unstaked lamports from the stake account
    ///
    /// Expects 3 Accounts:
    ///    0 - Delegate StakeAccount
    ///    1 - System account to which the lamports will be transferred,
    ///    2 - Syscall Account that carries epoch
    ///    3 - StakeHistory sysvar that carries stake warmup/cooldown history
    ///
    /// The u64 is the portion of the Stake account balance to be withdrawn,
    ///    must be <= StakeAccount.lamports - staked lamports
    Withdraw(u64),

    /// Deactivates the stake in the account
    ///
    /// Expects 2 Accounts:
    ///    0 - Delegate StakeAccount
    ///    1 - VoteAccount to which the Stake is delegated
    ///    2 - Syscall Account that carries epoch
    Deactivate,
}

pub fn create_stake_account_with_lockup(
    from_pubkey: &Pubkey,
    stake_pubkey: &Pubkey,
    lamports: u64,
    lockup: Slot,
) -> Vec<Instruction> {
    vec![
        system_instruction::create_account(
            from_pubkey,
            stake_pubkey,
            lamports,
            std::mem::size_of::<StakeState>() as u64,
            &id(),
        ),
        Instruction::new(
            id(),
            &StakeInstruction::Lockup(lockup),
            vec![AccountMeta::new(*stake_pubkey, false)],
        ),
    ]
}

pub fn create_stake_account(
    from_pubkey: &Pubkey,
    stake_pubkey: &Pubkey,
    lamports: u64,
) -> Vec<Instruction> {
    create_stake_account_with_lockup(from_pubkey, stake_pubkey, lamports, 0)
}

pub fn create_stake_account_and_delegate_stake(
    from_pubkey: &Pubkey,
    stake_pubkey: &Pubkey,
    vote_pubkey: &Pubkey,
    lamports: u64,
) -> Vec<Instruction> {
    let mut instructions = create_stake_account(from_pubkey, stake_pubkey, lamports);
    instructions.push(delegate_stake(stake_pubkey, vote_pubkey, lamports));
    instructions
}

pub fn redeem_vote_credits(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
    let account_metas = vec![
        AccountMeta::new(*stake_pubkey, false),
        AccountMeta::new_credit_only(*vote_pubkey, false),
        AccountMeta::new(crate::rewards_pools::random_id(), false),
        AccountMeta::new_credit_only(sysvar::rewards::id(), false),
        AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
    ];
    Instruction::new(id(), &StakeInstruction::RedeemVoteCredits, account_metas)
}

pub fn delegate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey, stake: u64) -> Instruction {
    let account_metas = vec![
        AccountMeta::new(*stake_pubkey, true),
        AccountMeta::new_credit_only(*vote_pubkey, false),
        AccountMeta::new_credit_only(sysvar::clock::id(), false),
        AccountMeta::new_credit_only(crate::config::id(), false),
    ];
    Instruction::new(id(), &StakeInstruction::DelegateStake(stake), account_metas)
}

pub fn withdraw(stake_pubkey: &Pubkey, to_pubkey: &Pubkey, lamports: u64) -> Instruction {
    let account_metas = vec![
        AccountMeta::new(*stake_pubkey, true),
        AccountMeta::new_credit_only(*to_pubkey, false),
        AccountMeta::new_credit_only(sysvar::clock::id(), false),
        AccountMeta::new_credit_only(sysvar::stake_history::id(), false),
    ];
    Instruction::new(id(), &StakeInstruction::Withdraw(lamports), account_metas)
}

pub fn deactivate_stake(stake_pubkey: &Pubkey, vote_pubkey: &Pubkey) -> Instruction {
    let account_metas = vec![
        AccountMeta::new(*stake_pubkey, true),
        AccountMeta::new_credit_only(*vote_pubkey, false),
        AccountMeta::new_credit_only(sysvar::clock::id(), false),
    ];
    Instruction::new(id(), &StakeInstruction::Deactivate, account_metas)
}

pub fn process_instruction(
    _program_id: &Pubkey,
    keyed_accounts: &mut [KeyedAccount],
    data: &[u8],
) -> Result<(), InstructionError> {
    solana_logger::setup();

    trace!("process_instruction: {:?}", data);
    trace!("keyed_accounts: {:?}", keyed_accounts);

    if keyed_accounts.is_empty() {
        Err(InstructionError::InvalidInstructionData)?;
    }

    let (me, rest) = &mut keyed_accounts.split_at_mut(1);
    let me = &mut me[0];

    // TODO: data-driven unpack and dispatch of KeyedAccounts
    match deserialize(data).map_err(|_| InstructionError::InvalidInstructionData)? {
        StakeInstruction::Lockup(slot) => me.lockup(slot),
        StakeInstruction::DelegateStake(stake) => {
            if rest.len() != 3 {
                Err(InstructionError::InvalidInstructionData)?;
            }
            let vote = &rest[0];

            me.delegate_stake(
                vote,
                stake,
                &sysvar::clock::from_keyed_account(&rest[1])?,
                &config::from_keyed_account(&rest[2])?,
            )
        }
        StakeInstruction::RedeemVoteCredits => {
            if rest.len() != 4 {
                Err(InstructionError::InvalidInstructionData)?;
            }
            let (vote, rest) = rest.split_at_mut(1);
            let vote = &mut vote[0];
            let (rewards_pool, rest) = rest.split_at_mut(1);
            let rewards_pool = &mut rewards_pool[0];

            me.redeem_vote_credits(
                vote,
                rewards_pool,
                &sysvar::rewards::from_keyed_account(&rest[0])?,
                &sysvar::stake_history::from_keyed_account(&rest[1])?,
            )
        }
        StakeInstruction::Withdraw(lamports) => {
            if rest.len() != 3 {
                Err(InstructionError::InvalidInstructionData)?;
            }
            let (to, sysvar) = &mut rest.split_at_mut(1);
            let mut to = &mut to[0];

            me.withdraw(
                lamports,
                &mut to,
                &sysvar::clock::from_keyed_account(&sysvar[0])?,
                &sysvar::stake_history::from_keyed_account(&sysvar[1])?,
            )
        }
        StakeInstruction::Deactivate => {
            if rest.len() != 2 {
                Err(InstructionError::InvalidInstructionData)?;
            }
            let (vote, rest) = rest.split_at_mut(1);
            let vote = &mut vote[0];
            let clock = &rest[0];

            me.deactivate_stake(vote, &sysvar::clock::from_keyed_account(&clock)?)
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use bincode::serialize;
    use solana_sdk::{account::Account, sysvar::stake_history::StakeHistory};

    fn process_instruction(instruction: &Instruction) -> Result<(), InstructionError> {
        let mut accounts: Vec<_> = instruction
            .accounts
            .iter()
            .map(|meta| {
                if sysvar::clock::check_id(&meta.pubkey) {
                    sysvar::clock::create_account(1, 0, 0, 0, 0)
                } else if sysvar::rewards::check_id(&meta.pubkey) {
                    sysvar::rewards::create_account(1, 0.0, 0.0)
                } else if sysvar::stake_history::check_id(&meta.pubkey) {
                    sysvar::stake_history::create_account(1, &StakeHistory::default())
                } else if config::check_id(&meta.pubkey) {
                    config::create_account(1, &config::Config::default())
                } else {
                    Account::default()
                }
            })
            .collect();

        {
            let mut keyed_accounts: Vec<_> = instruction
                .accounts
                .iter()
                .zip(accounts.iter_mut())
                .map(|(meta, account)| KeyedAccount::new(&meta.pubkey, meta.is_signer, account))
                .collect();
            super::process_instruction(&Pubkey::default(), &mut keyed_accounts, &instruction.data)
        }
    }

    #[test]
    fn test_stake_process_instruction() {
        assert_eq!(
            process_instruction(&redeem_vote_credits(&Pubkey::default(), &Pubkey::default())),
            Err(InstructionError::InvalidAccountData),
        );
        assert_eq!(
            process_instruction(&delegate_stake(&Pubkey::default(), &Pubkey::default(), 0)),
            Err(InstructionError::InvalidAccountData),
        );
        assert_eq!(
            process_instruction(&withdraw(&Pubkey::default(), &Pubkey::new_rand(), 100)),
            Err(InstructionError::InvalidAccountData),
        );
        assert_eq!(
            process_instruction(&deactivate_stake(&Pubkey::default(), &Pubkey::default())),
            Err(InstructionError::InvalidAccountData),
        );
    }

    #[test]
    fn test_stake_process_instruction_decode_bail() {
        // these will not call stake_state, have bogus contents

        // gets the first check
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [KeyedAccount::new(
                    &Pubkey::default(),
                    false,
                    &mut Account::default(),
                )],
                &serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
            ),
            Err(InstructionError::InvalidInstructionData),
        );

        // gets the sub-check for number of args
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [KeyedAccount::new(
                    &Pubkey::default(),
                    false,
                    &mut Account::default()
                ),],
                &serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
            ),
            Err(InstructionError::InvalidInstructionData),
        );

        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                ],
                &serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
            ),
            Err(InstructionError::InvalidInstructionData),
        );

        // gets the check non-deserialize-able account in delegate_stake
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), true, &mut Account::default()),
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(
                        &sysvar::clock::id(),
                        false,
                        &mut sysvar::clock::create_account(1, 0, 0, 0, 0)
                    ),
                    KeyedAccount::new(
                        &config::id(),
                        false,
                        &mut config::create_account(1, &config::Config::default())
                    ),
                ],
                &serialize(&StakeInstruction::DelegateStake(0)).unwrap(),
            ),
            Err(InstructionError::InvalidAccountData),
        );

        // gets the deserialization checks in redeem_vote_credits
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(
                        &sysvar::rewards::id(),
                        false,
                        &mut sysvar::rewards::create_account(1, 0.0, 0.0)
                    ),
                    KeyedAccount::new(
                        &sysvar::stake_history::id(),
                        false,
                        &mut sysvar::stake_history::create_account(1, &StakeHistory::default())
                    ),
                ],
                &serialize(&StakeInstruction::RedeemVoteCredits).unwrap(),
            ),
            Err(InstructionError::InvalidAccountData),
        );

        // Tests 3rd keyed account is of correct type (Clock instead of rewards) in withdraw
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(
                        &sysvar::rewards::id(),
                        false,
                        &mut sysvar::rewards::create_account(1, 0.0, 0.0)
                    ),
                    KeyedAccount::new(
                        &sysvar::stake_history::id(),
                        false,
                        &mut sysvar::stake_history::create_account(1, &StakeHistory::default())
                    ),
                ],
                &serialize(&StakeInstruction::Withdraw(42)).unwrap(),
            ),
            Err(InstructionError::InvalidArgument),
        );

        // Tests correct number of accounts are provided in withdraw
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(
                        &sysvar::clock::id(),
                        false,
                        &mut sysvar::rewards::create_account(1, 0.0, 0.0)
                    ),
                    KeyedAccount::new(
                        &sysvar::stake_history::id(),
                        false,
                        &mut sysvar::stake_history::create_account(1, &StakeHistory::default())
                    ),
                ],
                &serialize(&StakeInstruction::Withdraw(42)).unwrap(),
            ),
            Err(InstructionError::InvalidInstructionData),
        );

        // Tests 2nd keyed account is of correct type (Clock instead of rewards) in deactivate
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(
                        &sysvar::rewards::id(),
                        false,
                        &mut sysvar::rewards::create_account(1, 0.0, 0.0)
                    ),
                ],
                &serialize(&StakeInstruction::Deactivate).unwrap(),
            ),
            Err(InstructionError::InvalidArgument),
        );

        // Tests correct number of accounts are provided in deactivate
        assert_eq!(
            super::process_instruction(
                &Pubkey::default(),
                &mut [
                    KeyedAccount::new(&Pubkey::default(), false, &mut Account::default()),
                    KeyedAccount::new(
                        &sysvar::clock::id(),
                        false,
                        &mut sysvar::rewards::create_account(1, 0.0, 0.0)
                    ),
                ],
                &serialize(&StakeInstruction::Deactivate).unwrap(),
            ),
            Err(InstructionError::InvalidInstructionData),
        );
    }

}


text:
use std::collections::VecDeque;
use std::option::Option;
use std::str::Chars;

pub struct NPeekable<'a> {
    lookup: VecDeque<char>,
    char_iter: Chars<'a> }

    impl<'a> NPeekable<'a> {
        pub fn new(s: &str) -> NPeekable {
            NPeekable { lookup: VecDeque::new(), char_iter: s.chars() }
        }

        pub fn next(&mut self) -> Option<char> {
            if self.lookup.len() > 0 {
                self.lookup.pop_front()
            } else {
                self.char_iter.next()
            }
        }

        pub fn peek(&mut self) -> Option<&char> {
            self.n_peek(1)
        }

        pub fn n_peek(&mut self, n: usize) -> Option<&char> {
            if n == 0 {
                return None;
            }
            if n > self.lookup.len() {
                for _ in 0..(n - self.lookup.len()) {
                    self.lookup.push_back(self.char_iter.next()?);
                }
            }
            self.lookup.get(n - 1)
        }
    }

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

    #[test]
    fn n_peekable() {
        let mut char_iter = NPeekable::new("012345");
        assert_eq!(char_iter.n_peek(0).is_none(), true);

        assert_eq!(char_iter.peek().unwrap(), &'0');
        assert_eq!(char_iter.n_peek(1).unwrap(), &'0');
        assert_eq!(char_iter.n_peek(3).unwrap(), &'2');
        assert_eq!(char_iter.n_peek(100).is_none(), true);

        assert_eq!(char_iter.next().unwrap(), '0');
        assert_eq!(char_iter.next().unwrap(), '1');
        assert_eq!(char_iter.next().unwrap(), '2');

        assert_eq!(char_iter.peek().unwrap(), &'3');
        assert_eq!(char_iter.n_peek(2).unwrap(), &'4');
        assert_eq!(char_iter.peek().unwrap(), &'3');

        assert_eq!(char_iter.next().unwrap(), '3');
        assert_eq!(char_iter.next().unwrap(), '4');
        assert_eq!(char_iter.next().unwrap(), '5');
        assert_eq!(char_iter.next().is_none(), true);
        assert_eq!(char_iter.next().is_none(), true);

        assert_eq!(char_iter.peek().is_none(), true);
        assert_eq!(char_iter.n_peek(2).is_none(), true);
    }
}

domain: rust


text:
//! Lexical region resolution.

use crate::infer::region_constraints::Constraint;
use crate::infer::region_constraints::GenericKind;
use crate::infer::region_constraints::RegionConstraintData;
use crate::infer::region_constraints::VarInfos;
use crate::infer::region_constraints::VerifyBound;
use crate::infer::RegionRelations;
use crate::infer::RegionVariableOrigin;
use crate::infer::SubregionOrigin;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::implementation::{
    Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_data_structures::intern::Interned;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic};
use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar};
use rustc_middle::ty::{Region, RegionVid};
use rustc_span::Span;
use std::fmt;

/// This function performs lexical region resolution given a complete
/// set of constraints and variable origins. It performs a fixed-point
/// iteration to find region values which satisfy all constraints,
/// assuming such values can be found. It returns the final values of
/// all the variables as well as a set of errors that must be reported.
#[instrument(level = "debug", skip(region_rels, var_infos, data))]
pub(crate) fn resolve<'tcx>(
    region_rels: &RegionRelations<'_, 'tcx>,
    var_infos: VarInfos,
    data: RegionConstraintData<'tcx>,
) -> (LexicalRegionResolutions<'tcx>, Vec<RegionResolutionError<'tcx>>) {
    let mut errors = vec![];
    let mut resolver = LexicalResolver { region_rels, var_infos, data };
    let values = resolver.infer_variable_values(&mut errors);
    (values, errors)
}

/// Contains the result of lexical region resolution. Offers methods
/// to lookup up the final value of a region variable.
#[derive(Clone)]
pub struct LexicalRegionResolutions<'tcx> {
    pub(crate) values: IndexVec<RegionVid, VarValue<'tcx>>,
    pub(crate) error_region: ty::Region<'tcx>,
}

#[derive(Copy, Clone, Debug)]
pub(crate) enum VarValue<'tcx> {
    Value(Region<'tcx>),
    ErrorValue,
}

#[derive(Clone, Debug)]
pub enum RegionResolutionError<'tcx> {
    /// `ConcreteFailure(o, a, b)`:
    ///
    /// `o` requires that `a <= b`, but this does not hold
    ConcreteFailure(SubregionOrigin<'tcx>, Region<'tcx>, Region<'tcx>),

    /// `GenericBoundFailure(p, s, a)
    ///
    /// The parameter/associated-type `p` must be known to outlive the lifetime
    /// `a` (but none of the known bounds are sufficient).
    GenericBoundFailure(SubregionOrigin<'tcx>, GenericKind<'tcx>, Region<'tcx>),

    /// `SubSupConflict(v, v_origin, sub_origin, sub_r, sup_origin, sup_r)`:
    ///
    /// Could not infer a value for `v` (which has origin `v_origin`)
    /// because `sub_r <= v` (due to `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and
    /// `sub_r <= sup_r` does not hold.
    SubSupConflict(
        RegionVid,
        RegionVariableOrigin,
        SubregionOrigin<'tcx>,
        Region<'tcx>,
        SubregionOrigin<'tcx>,
        Region<'tcx>,
        Vec<Span>, // All the influences on a given value that didn't meet its constraints.
    ),

    /// Indicates a `'b: 'a` constraint where `'a` is in a universe that
    /// cannot name the placeholder `'b`.
    UpperBoundUniverseConflict(
        RegionVid,
        RegionVariableOrigin,
        ty::UniverseIndex,     // the universe index of the region variable
        SubregionOrigin<'tcx>, // cause of the constraint
        Region<'tcx>,          // the placeholder `'b`
    ),
}

struct RegionAndOrigin<'tcx> {
    region: Region<'tcx>,
    origin: SubregionOrigin<'tcx>,
}

type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>;

struct LexicalResolver<'cx, 'tcx> {
    region_rels: &'cx RegionRelations<'cx, 'tcx>,
    var_infos: VarInfos,
    data: RegionConstraintData<'tcx>,
}

impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
    fn tcx(&self) -> TyCtxt<'tcx> {
        self.region_rels.tcx
    }

    fn infer_variable_values(
        &mut self,
        errors: &mut Vec<RegionResolutionError<'tcx>>,
    ) -> LexicalRegionResolutions<'tcx> {
        let mut var_data = self.construct_var_data(self.tcx());

        // Dorky hack to cause `dump_constraints` to only get called
        // if debug mode is enabled:
        debug!(
            "----() End constraint listing (context={:?}) {:?}---",
            self.region_rels.context,
            self.dump_constraints(self.region_rels)
        );

        let graph = self.construct_graph();
        self.expand_givens(&graph);
        self.expansion(&mut var_data);
        self.collect_errors(&mut var_data, errors);
        self.collect_var_errors(&var_data, &graph, errors);
        var_data
    }

    fn num_vars(&self) -> usize {
        self.var_infos.len()
    }

    /// Initially, the value for all variables is set to `'empty`, the
    /// empty region. The `expansion` phase will grow this larger.
    fn construct_var_data(&self, tcx: TyCtxt<'tcx>) -> LexicalRegionResolutions<'tcx> {
        LexicalRegionResolutions {
            error_region: tcx.lifetimes.re_static,
            values: IndexVec::from_fn_n(
                |vid| {
                    let vid_universe = self.var_infos[vid].universe;
                    let re_empty = tcx.mk_region(ty::ReEmpty(vid_universe));
                    VarValue::Value(re_empty)
                },
                self.num_vars(),
            ),
        }
    }

    fn dump_constraints(&self, free_regions: &RegionRelations<'_, 'tcx>) {
        debug!("----() Start constraint listing (context={:?}) ()----", free_regions.context);
        for (idx, (constraint, _)) in self.data.constraints.iter().enumerate() {
            debug!("Constraint {} => {:?}", idx, constraint);
        }
    }

    fn expand_givens(&mut self, graph: &RegionGraph<'_>) {
        // Givens are a kind of horrible hack to account for
        // constraints like 'c <= '0 that are known to hold due to
        // closure signatures (see the comment above on the `givens`
        // field). They should go away. But until they do, the role
        // of this fn is to account for the transitive nature:
        //
        //     Given 'c <= '0
        //     and   '0 <= '1
        //     then  'c <= '1

        let seeds: Vec<_> = self.data.givens.iter().cloned().collect();
        for (r, vid) in seeds {
            // While all things transitively reachable in the graph
            // from the variable (`'0` in the example above).
            let seed_index = NodeIndex(vid.index() as usize);
            for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
                let succ_index = succ_index.0;

                // The first N nodes correspond to the region
                // variables. Other nodes correspond to constant
                // regions.
                if succ_index < self.num_vars() {
                    let succ_vid = RegionVid::new(succ_index);

                    // Add `'c <= '1`.
                    self.data.givens.insert((r, succ_vid));
                }
            }
        }
    }

    fn expansion(&self, var_values: &mut LexicalRegionResolutions<'tcx>) {
        let mut constraints = IndexVec::from_elem_n(Vec::new(), var_values.values.len());
        let mut changes = Vec::new();
        for constraint in self.data.constraints.keys() {
            let (a_vid, a_region, b_vid, b_data) = match *constraint {
                Constraint::RegSubVar(a_region, b_vid) => {
                    let b_data = var_values.value_mut(b_vid);
                    (None, a_region, b_vid, b_data)
                }
                Constraint::VarSubVar(a_vid, b_vid) => match *var_values.value(a_vid) {
                    VarValue::ErrorValue => continue,
                    VarValue::Value(a_region) => {
                        let b_data = var_values.value_mut(b_vid);
                        (Some(a_vid), a_region, b_vid, b_data)
                    }
                },
                Constraint::RegSubReg(..) | Constraint::VarSubReg(..) => {
                    // These constraints are checked after expansion
                    // is done, in `collect_errors`.
                    continue;
                }
            };
            if self.expand_node(a_region, b_vid, b_data) {
                changes.push(b_vid);
            }
            if let Some(a_vid) = a_vid {
                match b_data {
                    VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue => (),
                    _ => {
                        constraints[a_vid].push((a_vid, b_vid));
                        constraints[b_vid].push((a_vid, b_vid));
                    }
                }
            }
        }

        while let Some(vid) = changes.pop() {
            constraints[vid].retain(|&(a_vid, b_vid)| {
                let VarValue::Value(a_region) = *var_values.value(a_vid) else {
                    return false;
                };
                let b_data = var_values.value_mut(b_vid);
                if self.expand_node(a_region, b_vid, b_data) {
                    changes.push(b_vid);
                }
                !matches!(
                    b_data,
                    VarValue::Value(Region(Interned(ReStatic, _))) | VarValue::ErrorValue
                )
            });
        }
    }

    fn expand_node(
        &self,
        a_region: Region<'tcx>,
        b_vid: RegionVid,
        b_data: &mut VarValue<'tcx>,
    ) -> bool {
        debug!("expand_node({:?}, {:?} == {:?})", a_region, b_vid, b_data);

        match *a_region {
            // Check if this relationship is implied by a given.
            ty::ReEarlyBound(_) | ty::ReFree(_) => {
                if self.data.givens.contains(&(a_region, b_vid)) {
                    debug!("given");
                    return false;
                }
            }

            _ => {}
        }

        match *b_data {
            VarValue::Value(cur_region) => {
                // This is a specialized version of the `lub_concrete_regions`
                // check below for a common case, here purely as an
                // optimization.
                let b_universe = self.var_infos[b_vid].universe;
                if let ReEmpty(a_universe) = *a_region && a_universe == b_universe {
                    return false;
                }

                let mut lub = self.lub_concrete_regions(a_region, cur_region);
                if lub == cur_region {
                    return false;
                }

                // Watch out for `'b: !1` relationships, where the
                // universe of `'b` can't name the placeholder `!1`. In
                // that case, we have to grow `'b` to be `'static` for the
                // relationship to hold. This is obviously a kind of sub-optimal
                // choice -- in the future, when we incorporate a knowledge
                // of the parameter environment, we might be able to find a
                // tighter bound than `'static`.
                //
                // (This might e.g. arise from being asked to prove `for<'a> { 'b: 'a }`.)
                if let ty::RePlaceholder(p) = *lub && b_universe.cannot_name(p.universe) {
                    lub = self.tcx().lifetimes.re_static;
                }

                debug!("Expanding value of {:?} from {:?} to {:?}", b_vid, cur_region, lub);

                *b_data = VarValue::Value(lub);
                true
            }

            VarValue::ErrorValue => false,
        }
    }

    /// True if `a <= b`, but not defined over inference variables.
    #[instrument(level = "trace", skip(self))]
    fn sub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> bool {
        let tcx = self.tcx();
        let sub_free_regions = |r1, r2| self.region_rels.free_regions.sub_free_regions(tcx, r1, r2);

        // Check for the case where we know that `'b: 'static` -- in that case,
        // `a <= b` for all `a`.
        let b_free_or_static = self.region_rels.free_regions.is_free_or_static(b);
        if b_free_or_static && sub_free_regions(tcx.lifetimes.re_static, b) {
            return true;
        }

        // If both `a` and `b` are free, consult the declared
        // relationships.  Note that this can be more precise than the
        // `lub` relationship defined below, since sometimes the "lub"
        // is actually the `postdom_upper_bound` (see
        // `TransitiveRelation` for more details).
        let a_free_or_static = self.region_rels.free_regions.is_free_or_static(a);
        if a_free_or_static && b_free_or_static {
            return sub_free_regions(a, b);
        }

        // For other cases, leverage the LUB code to find the LUB and
        // check if it is equal to `b`.
        self.lub_concrete_regions(a, b) == b
    }

    /// Returns the least-upper-bound of `a` and `b`; i.e., the
    /// smallest region `c` such that `a <= c` and `b <= c`.
    ///
    /// Neither `a` nor `b` may be an inference variable (hence the
    /// term "concrete regions").
    #[instrument(level = "trace", skip(self))]
    fn lub_concrete_regions(&self, a: Region<'tcx>, b: Region<'tcx>) -> Region<'tcx> {
        let r = match (*a, *b) {
            (ReLateBound(..), _) | (_, ReLateBound(..)) | (ReErased, _) | (_, ReErased) => {
                bug!("cannot relate region: LUB({:?}, {:?})", a, b);
            }

            (ReVar(v_id), _) | (_, ReVar(v_id)) => {
                span_bug!(
                    self.var_infos[v_id].origin.span(),
                    "lub_concrete_regions invoked with non-concrete \
                     regions: {:?}, {:?}",
                    a,
                    b
                );
            }

            (ReStatic, _) | (_, ReStatic) => {
                // nothing lives longer than `'static`
                self.tcx().lifetimes.re_static
            }

            (ReEmpty(_), ReEarlyBound(_) | ReFree(_)) => {
                // All empty regions are less than early-bound, free,
                // and scope regions.
                b
            }

            (ReEarlyBound(_) | ReFree(_), ReEmpty(_)) => {
                // All empty regions are less than early-bound, free,
                // and scope regions.
                a
            }

            (ReEmpty(a_ui), ReEmpty(b_ui)) => {
                // Empty regions are ordered according to the universe
                // they are associated with.
                let ui = a_ui.min(b_ui);
                self.tcx().mk_region(ReEmpty(ui))
            }

            (ReEmpty(empty_ui), RePlaceholder(placeholder))
            | (RePlaceholder(placeholder), ReEmpty(empty_ui)) => {
                // If this empty region is from a universe that can
                // name the placeholder, then the placeholder is
                // larger; otherwise, the only ancestor is `'static`.
                if empty_ui.can_name(placeholder.universe) {
                    self.tcx().mk_region(RePlaceholder(placeholder))
                } else {
                    self.tcx().lifetimes.re_static
                }
            }

            (ReEarlyBound(_) | ReFree(_), ReEarlyBound(_) | ReFree(_)) => {
                self.region_rels.lub_free_regions(a, b)
            }

            // For these types, we cannot define any additional
            // relationship:
            (RePlaceholder(..), _) | (_, RePlaceholder(..)) => {
                if a == b {
                    a
                } else {
                    self.tcx().lifetimes.re_static
                }
            }
        };

        debug!("lub_concrete_regions({:?}, {:?}) = {:?}", a, b, r);

        r
    }

    /// After expansion is complete, go and check upper bounds (i.e.,
    /// cases where the region cannot grow larger than a fixed point)
    /// and check that they are satisfied.
    #[instrument(skip(self, var_data, errors))]
    fn collect_errors(
        &self,
        var_data: &mut LexicalRegionResolutions<'tcx>,
        errors: &mut Vec<RegionResolutionError<'tcx>>,
    ) {
        for (constraint, origin) in &self.data.constraints {
            debug!(?constraint, ?origin);
            match *constraint {
                Constraint::RegSubVar(..) | Constraint::VarSubVar(..) => {
                    // Expansion will ensure that these constraints hold. Ignore.
                }

                Constraint::RegSubReg(sub, sup) => {
                    if self.sub_concrete_regions(sub, sup) {
                        continue;
                    }

                    debug!(
                        "region error at {:?}: \
                         cannot verify that {:?} <= {:?}",
                        origin, sub, sup
                    );

                    errors.push(RegionResolutionError::ConcreteFailure(
                        (*origin).clone(),
                        sub,
                        sup,
                    ));
                }

                Constraint::VarSubReg(a_vid, b_region) => {
                    let a_data = var_data.value_mut(a_vid);
                    debug!("contraction: {:?} == {:?}, {:?}", a_vid, a_data, b_region);

                    let VarValue::Value(a_region) = *a_data else {
                        continue;
                    };

                    // Do not report these errors immediately:
                    // instead, set the variable value to error and
                    // collect them later.
                    if !self.sub_concrete_regions(a_region, b_region) {
                        debug!(
                            "region error at {:?}: \
                            cannot verify that {:?}={:?} <= {:?}",
                            origin, a_vid, a_region, b_region
                        );
                        *a_data = VarValue::ErrorValue;
                    }
                }
            }
        }

        for verify in &self.data.verifys {
            debug!("collect_errors: verify={:?}", verify);
            let sub = var_data.normalize(self.tcx(), verify.region);

            let verify_kind_ty = verify.kind.to_ty(self.tcx());
            let verify_kind_ty = var_data.normalize(self.tcx(), verify_kind_ty);
            if self.bound_is_met(&verify.bound, var_data, verify_kind_ty, sub) {
                continue;
            }

            debug!(
                "collect_errors: region error at {:?}: \
                 cannot verify that {:?} <= {:?}",
                verify.origin, verify.region, verify.bound
            );

            errors.push(RegionResolutionError::GenericBoundFailure(
                verify.origin.clone(),
                verify.kind,
                sub,
            ));
        }
    }

    /// Go over the variables that were declared to be error variables
    /// and create a `RegionResolutionError` for each of them.
    fn collect_var_errors(
        &self,
        var_data: &LexicalRegionResolutions<'tcx>,
        graph: &RegionGraph<'tcx>,
        errors: &mut Vec<RegionResolutionError<'tcx>>,
    ) {
        debug!("collect_var_errors, var_data = {:#?}", var_data.values);

        // This is the best way that I have found to suppress
        // duplicate and related errors. Basically we keep a set of
        // flags for every node. Whenever an error occurs, we will
        // walk some portion of the graph looking to find pairs of
        // conflicting regions to report to the user. As we walk, we
        // trip the flags from false to true, and if we find that
        // we've already reported an error involving any particular
        // node we just stop and don't report the current error.  The
        // idea is to report errors that derive from independent
        // regions of the graph, but not those that derive from
        // overlapping locations.
        let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars());


text:
use cgmath::Vector2;
use wasm_rgame::Canvas;

pub enum TransformVector {
    Relative(Vector2<f32>),
    Absolute(Vector2<f32>),
}

#[derive(Clone)]
pub struct Transform {
    pub pos: Vector2<f32>,
    pub size: Vector2<f32>,
    pub pivot: Vector2<f32>,
}

impl Transform {
    pub fn new(pos: TransformVector, size: TransformVector, pivot: Vector2<f32>) -> Transform {
        Transform {
            pos: pos.into_absolute(),
            size: size.into_absolute(),
            pivot,
        }
    }

    pub fn contains(&self, point: Vector2<f32>) -> bool {
        let bottom_left = self.bottom_left();
        bottom_left.x <= point.x && point.x <= bottom_left.x + self.size.x &&
            bottom_left.y <= point.y && point.y <= bottom_left.y + self.size.y
    }

    pub fn bottom_left(&self) -> Vector2<f32> {
        Vector2 {
            x: self.pos.x - (self.pivot.x * self.size.x),
            y: self.pos.y - (self.pivot.y * self.size.y),
        }
    }

    pub fn center(&self) -> Vector2<f32> {
        self.bottom_left() + (self.size / 2.0)
    }
}

impl TransformVector {
    fn into_absolute(self) -> Vector2<f32> {
        match self {
            TransformVector::Absolute(vec) => vec,
            TransformVector::Relative(vec) => {
                let canvas = Canvas::instance();
                Vector2 {
                    x: vec.x * (canvas.width() as f32),
                    y: vec.y * (canvas.height() as f32),
                }
            }
        }
    }
}

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

    #[test]
    fn bottom_left_works() {
        let transform = Transform {
            pos: Vector2 { x: 2.0, y: 1.0, },
            size: Vector2 { x: 5.5, y: 6.5, },
            pivot: Vector2 { x: 0.5, y: 0.5, },
        };

        assert_eq!(transform.bottom_left(), Vector2 { x: -0.75, y: -2.25, });

        let transform2 = Transform {
            pos: Vector2 { x: 3.0, y: 5.0, },
            size: Vector2 { x: 5.5, y: 6.5, },
            pivot: Vector2 { x: 0.0, y: 0.0, },
        };

        assert_eq!(transform2.bottom_left(), Vector2 { x: 3.0, y: 5.0, });
    }

    #[test]
    fn contains_works() {
        let transform = Transform {
            pos: Vector2 { x: 2.0, y: 1.0, },
            size: Vector2 { x: 5.5, y: 6.5, },
            pivot: Vector2 { x: 0.5, y: 0.5, },
        };

        assert_eq!(transform.bottom_left(), Vector2 { x: -0.75, y: -2.25, });
        // top_right -> x: 4.75, y: 4.25

        assert_eq!(transform.contains(Vector2 { x: -0.76, y: -2.25, }), false);
        assert_eq!(transform.contains(Vector2 { x: -0.75, y: -2.25, }), true);
        assert_eq!(transform.contains(Vector2 { x: 0.0, y: 0.0, }), true);
        assert_eq!(transform.contains(Vector2 { x: 2.0, y: 1.0, }), true);
        assert_eq!(transform.contains(Vector2 { x: 4.75, y: 0.0, }), true);
        assert_eq!(transform.contains(Vector2 { x: 5.0, y: 0.0, }), false);
    }
}


text:
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// xfail-pretty - token trees can't pretty print

fn main() {

    macro_rules! mylambda_tt(
        ($x:ident, $body:expr) => ({
            fn f($x: int) -> int { return $body; };
            f
        })
    )

    assert(mylambda_tt!(y, y * 2)(8) == 16)
}


text:
// Copyright (c) 2018-2021 The MobileCoin Foundation

use alloc::vec::Vec;
use blake2::digest::Update;
use core::{convert::TryFrom, fmt};
use mc_account_keys::PublicAddress;
use mc_common::Hash;
use mc_crypto_digestible::{Digestible, MerlinTranscript};
use mc_crypto_hashes::Blake2b256;
use mc_crypto_keys::{CompressedRistrettoPublic, RistrettoPrivate, RistrettoPublic};
use mc_util_repr_bytes::{
    derive_prost_message_from_repr_bytes, typenum::U32, GenericArray, ReprBytes,
};
use prost::Message;
use serde::{Deserialize, Serialize};

use crate::{
    amount::{Amount, AmountError},
    domain_separators::TXOUT_CONFIRMATION_NUMBER_DOMAIN_TAG,
    encrypted_fog_hint::EncryptedFogHint,
    get_tx_out_shared_secret,
    membership_proofs::Range,
    memo::{EncryptedMemo, MemoPayload},
    onetime_keys::{create_shared_secret, create_tx_out_public_key, create_tx_out_target_key},
    ring_signature::{KeyImage, SignatureRctBulletproofs},
    CompressedCommitment, NewMemoError, NewTxError,
};

/// Transaction hash length, in bytes.
pub const TX_HASH_LEN: usize = 32;

#[derive(
    Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Digestible,
)]
/// Hash of a Tx.
pub struct TxHash(pub [u8; TX_HASH_LEN]);

impl TxHash {
    #[inline]
    /// Copies `self` to a new Vec.
    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }

    #[inline]
    /// A reference to the underlying byte array.
    pub fn as_bytes(&self) -> &[u8; TX_HASH_LEN] {
        &self.0
    }
}

impl core::ops::Deref for TxHash {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        &self.0
    }
}

impl From<&[u8; TX_HASH_LEN]> for TxHash {
    #[inline]
    fn from(a: &[u8; TX_HASH_LEN]) -> Self {
        Self(*a)
    }
}

impl From<[u8; TX_HASH_LEN]> for TxHash {
    #[inline]
    fn from(a: [u8; TX_HASH_LEN]) -> Self {
        Self(a)
    }
}

impl<'bytes> TryFrom<&'bytes [u8]> for TxHash {
    type Error = ();

    #[inline]
    fn try_from(src: &[u8]) -> Result<Self, <Self as TryFrom<&'bytes [u8]>>::Error> {
        if src.len() != TX_HASH_LEN {
            return Err(());
        }
        let mut bytes = [0u8; TX_HASH_LEN];
        bytes.copy_from_slice(src);
        Ok(Self::from(bytes))
    }
}

impl fmt::Display for TxHash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", hex_fmt::HexFmt(&self.0[0..6]))
    }
}

impl fmt::Debug for TxHash {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Tx#{}", self)
    }
}

/// A CryptoNote-style transaction.
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Message, Digestible)]
pub struct Tx {
    /// The transaction contents.
    #[prost(message, required, tag = "1")]
    pub prefix: TxPrefix,

    /// The transaction signature.
    #[prost(message, required, tag = "2")]
    pub signature: SignatureRctBulletproofs,
}

impl fmt::Display for Tx {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.tx_hash())
    }
}

impl Tx {
    /// Compute a 32-byte hash from all of the contents of a Tx
    pub fn tx_hash(&self) -> TxHash {
        TxHash::from(self.digest32::<MerlinTranscript>(b"mobilecoin-tx"))
    }

    /// Key images "spent" by this transaction.
    pub fn key_images(&self) -> Vec<KeyImage> {
        self.signature.key_images()
    }

    /// Get the highest index of each membership proof referenced by the
    /// transaction.
    pub fn get_membership_proof_highest_indices(&self) -> Vec<u64> {
        self.prefix.get_membership_proof_highest_indices()
    }

    /// Output public keys contained in this transaction.
    pub fn output_public_keys(&self) -> Vec<CompressedRistrettoPublic> {
        self.prefix
            .outputs
            .iter()
            .map(|tx_out| tx_out.public_key)
            .collect()
    }
}

/// TxPrefix is the Tx struct without the signature.  It is used to
/// calculate the prefix hash for signing and verifying.
#[derive(Clone, Deserialize, Eq, PartialEq, Serialize, Message, Digestible)]
pub struct TxPrefix {
    /// List of inputs to the transaction.
    #[prost(message, repeated, tag = "1")]
    pub inputs: Vec<TxIn>,

    /// List of outputs from the transaction.
    #[prost(message, repeated, tag = "2")]
    pub outputs: Vec<TxOut>,

    /// Fee paid to the foundation for this transaction
    #[prost(uint64, tag = "3")]
    pub fee: u64,

    /// The block index at which this transaction is no longer valid.
    #[prost(uint64, tag = "4")]
    pub tombstone_block: u64,
}

impl TxPrefix {
    /// Create a new TxPrefix.
    ///
    /// # Arguments:
    /// * `inputs` - Inputs spent by the transaction.
    /// * `outputs` - Outputs created by the transaction.
    /// * `fee` - Transaction fee.
    /// * `tombstone_block` - The block index at which this transaction is no
    ///   longer valid.
    pub fn new(inputs: Vec<TxIn>, outputs: Vec<TxOut>, fee: u64, tombstone_block: u64) -> TxPrefix {
        TxPrefix {
            inputs,
            outputs,
            fee,
            tombstone_block,
        }
    }

    /// Digestible-crate hash of `self` using Merlin
    pub fn hash(&self) -> TxHash {
        TxHash::from(self.digest32::<MerlinTranscript>(b"mobilecoin-tx-prefix"))
    }

    /// Return the `highest_index` for each tx_out membership proof in this
    /// transaction.
    pub fn get_membership_proof_highest_indices(&self) -> Vec<u64> {
        self.inputs
            .iter()
            .flat_map(|tx_in| {
                let indices: Vec<u64> = tx_in
                    .proofs
                    .iter()
                    .map(|tx_out_membership_proof| tx_out_membership_proof.highest_index)
                    .collect();
                indices
            })
            .collect()
    }

    /// Get all output commitments.
    pub fn output_commitments(&self) -> Vec<CompressedCommitment> {
        self.outputs
            .iter()
            .map(|output| output.amount.commitment)
            .collect()
    }
}

/// An "input" to a transaction.
#[derive(Clone, Deserialize, Eq, PartialEq, Serialize, Message, Digestible)]
pub struct TxIn {
    /// A "ring" of outputs containing the single output that is being spent.
    /// It would be nice to use [TxOut; RING_SIZE] here, but Prost only works
    /// with Vec.
    #[prost(message, repeated, tag = "1")]
    pub ring: Vec<TxOut>,

    /// Proof that each TxOut in `ring` is in the ledger.
    /// It would be nice to use [TxOutMembershipProof; RING_SIZE] here, but
    /// Prost only works with Vec.
    #[prost(message, repeated, tag = "2")]
    pub proofs: Vec<TxOutMembershipProof>,
}

/// An output created by a transaction.
#[derive(Clone, Deserialize, Eq, Hash, PartialEq, Serialize, Message, Digestible)]
pub struct TxOut {
    /// The amount being sent.
    #[prost(message, required, tag = "1")]
    pub amount: Amount,

    /// The one-time public address of this output.
    #[prost(message, required, tag = "2")]
    pub target_key: CompressedRistrettoPublic,

    /// The per output tx public key
    #[prost(message, required, tag = "3")]
    pub public_key: CompressedRistrettoPublic,

    /// The encrypted fog hint for the fog ingest server.
    #[prost(message, required, tag = "4")]
    pub e_fog_hint: EncryptedFogHint,

    /// The encrypted memo (except for old TxOut's, which don't have this.)
    #[prost(message, tag = "5")]
    pub e_memo: Option<EncryptedMemo>,
}

/// When creating a MemoPayload for a TxOut, sometimes it is important to be
/// able to have access to the fields of this TxOut. For example, in some of
/// the authenticated memos, the memo contains an HMAC, which includes the
/// tx_out_public_key, in order to bind the memo to the TxOut.
///
/// However, the TxOut public key is not created until `TxOut::new` is already
/// being called. We also want for `TxOut::new` to be responsible to encrypt
/// the memo using the shared secret. So this means that `TxOut::new_with_memo`
/// needs to take a callback which produces the memo and has access to these
/// intermediate variables.
///
/// The intermediate variables that we provide to the memo callback are gathered
/// up into a MemoContext object, and this is passed to the callback. This makes
/// the callbacks more readable and it makes it easy to pass new variables into
/// the callbacks in the future if needed without disrupting existing working
/// code.
pub struct MemoContext<'a> {
    /// The tx_public_key of the TxOut we are creating that we need a memo for
    pub tx_public_key: &'a RistrettoPublic,
}

impl TxOut {
    /// Creates a TxOut that sends `value` to `recipient`.
    /// This uses a defaulted (all zeroes) MemoPayload.
    ///
    /// # Arguments
    /// * `value` - Value of the output.
    /// * `recipient` - Recipient's address.
    /// * `tx_private_key` - The transaction's private key
    /// * `hint` - Encrypted Fog hint for this output.
    pub fn new(
        value: u64,
        recipient: &PublicAddress,
        tx_private_key: &RistrettoPrivate,
        hint: EncryptedFogHint,
    ) -> Result<Self, AmountError> {
        TxOut::new_with_memo(value, recipient, tx_private_key, hint, |_| {
            Ok(Some(MemoPayload::default()))
        })
        .map_err(|err| match err {
            NewTxError::Amount(err) => err,
            // Memo error is unreachable because the memo_fn we passed is infallible
            NewTxError::Memo(_) => unreachable!(),
        })
    }

    /// Creates a TxOut that sends `value` to `recipient`, with a custom memo
    /// attached. The memo is produced by a callback function which is
    /// passed the value and tx_public_key.
    ///
    /// # Arguments
    /// * `value` - Value of the output.
    /// * `recipient` - Recipient's address.
    /// * `tx_private_key` - The transaction's private key
    /// * `hint` - Encrypted Fog hint.
    /// * `memo_fn` - A callback taking MemoContext, which produces a
    ///   MemoPayload, or a NewMemo error
    pub fn new_with_memo(
        value: u64,
        recipient: &PublicAddress,
        tx_private_key: &RistrettoPrivate,
        hint: EncryptedFogHint,
        memo_fn: impl FnOnce(MemoContext) -> Result<Option<MemoPayload>, NewMemoError>,
    ) -> Result<Self, NewTxError> {
        let target_key = create_tx_out_target_key(tx_private_key, recipient).into();
        let public_key = create_tx_out_public_key(tx_private_key, recipient.spend_public_key());

        let shared_secret = create_shared_secret(recipient.view_public_key(), tx_private_key);

        let amount = Amount::new(value, &shared_secret)?;

        let memo_ctxt = MemoContext {
            tx_public_key: &public_key,
        };
        let memo = memo_fn(memo_ctxt).map_err(NewTxError::Memo)?;
        let e_memo = memo.map(|memo| memo.encrypt(&shared_secret));

        Ok(TxOut {
            amount,
            target_key,
            public_key: public_key.into(),
            e_fog_hint: hint,
            e_memo,
        })
    }

    /// A merlin-based hash of this TxOut.
    pub fn hash(&self) -> Hash {
        self.digest32::<MerlinTranscript>(b"mobilecoin-txout")
    }

    /// Try to decrypt the e_memo field, using the TxOut shared secret.
    ///
    /// This function is backwards-compatible in the following sense:
    /// - If self.e_memo is empty (a TxOut from before this field was added), we
    ///   return MemoPayload corresponding to "unused memo".
    /// - If self.e_memo is present, we use MemoPayload::try_decrypt. This
    ///   succeeds unless the e_memo has an invalid length.
    ///
    /// Note that the results of this function call are unauthenticated.
    ///
    /// The next step is usually to call MemoType::try_from to determine what
    /// memo type this is, see transaction_std::memo module.
    pub fn decrypt_memo(&self, tx_out_shared_secret: &RistrettoPublic) -> MemoPayload {
        if let Some(e_memo) = self.e_memo {
            e_memo.decrypt(tx_out_shared_secret)
        } else {
            MemoPayload::default()
        }
    }
}

/// A Merkle proof-of-membership for the TxOut at the given index contains a set
/// of hashes: it includes each hash between the leaf and the root, as well as
/// each "other" child hash. It is assumed that the proof accompanies the leaf
/// TxOut, so its leaf hash may be computed as part of checking the proof.
///
/// In total, the TxOut, its index, and the set of non-leaf hashes are
/// sufficient to re-compute the root hash, which completes the
/// proof-of-membership verification.
///
/// # References
/// * [How Log Proofs Work](http://www.certificate-transparency.org/log-proofs-work)
#[derive(Clone, Deserialize, Eq, PartialEq, Serialize, Message, Digestible)]
pub struct TxOutMembershipProof {
    /// Index of the TxOut that this proof refers to.
    #[prost(uint64, tag = "1")]
    pub index: u64,

    /// Index of the last TxOut at the time the proof was created.
    #[prost(uint64, tag = "2")]
    pub highest_index: u64,

    /// All hashes needed to recompute the root hash.
    /// These elements must be listed in the order in which they should be
    /// combined for the proof to be valid.
    #[prost(message, repeated, tag = "3")]
    pub elements: Vec<TxOutMembershipElement>,
}

impl TxOutMembershipProof {
    /// Create a Merkle proof-of-membership for a given TxOut.
    ///
    /// # Arguments
    /// * `index` - The index of the TxOut.
    /// * `highest_index` - The index of the last TxOut in the ledger,
    ///   indicating the size of the tree that the proof refers to.
    /// * `elements` - The tx out membership elements, containing ranges
    ///   referring to subtrees in the tree, and hashes. These must be provided
    ///   in the order in which they should be combined to validate the proof.
    pub fn new(index: u64, highest_index: u64, elements: Vec<TxOutMembershipElement>) -> Self {
        Self {
            index,
            highest_index,
            elements,
        }
    }
}

#[derive(Clone, Deserialize, Eq, PartialOrd, Ord, PartialEq, Serialize, Message, Digestible)]
/// An element of a TxOut membership proof, denoting an internal hash node in a
/// Merkle tree.
pub struct TxOutMembershipElement {
    /// The range of leaf nodes "under" this internal hash.
    #[prost(message, required, tag = "1")]
    pub range: Range,

    #[prost(message, required, tag = "2")]
    /// The internal hash value.
    pub hash: TxOutMembershipHash,
}

impl TxOutMembershipElement {
    pub fn new(range: Range, hash: [u8; 32]) -> Self {
        Self {
            range,
            hash: hash.into(),
        }
    }
}

#[derive(
    Clone, Deserialize, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Debug, Digestible,
)]
#[digestible(transparent)]
/// A hash in a TxOut membership proof.
pub struct TxOutMembershipHash(pub [u8; 32]);

impl TxOutMembershipHash {
    /// Copies self into a new Vec.
    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }
}

impl core::convert::AsRef<[u8; 32]> for TxOutMembershipHash {
    #[inline]
    fn as_ref(&self) -> &[u8; 32] {
        &self.0
    }
}

impl core::convert::From<&[u8; 32]> for TxOutMembershipHash {
    #[inline]
    fn from(src: &[u8; 32]) -> Self {
        Self(*src)
    }
}

impl core::convert::From<[u8; 32]> for TxOutMembershipHash {
    #[inline]
    fn from(src: [u8; 32]) -> Self {
        Self(src)
    }
}

impl ReprBytes for TxOutMembershipHash {
    type Error = &'static str;
    type Size = U32;
    fn from_bytes(src: &GenericArray<u8, U32>) -> Result<Self, &'static str> {
        Ok(Self((*src).into()))
    }
    fn to_bytes(&self) -> GenericArray<u8, U32> {
        self.0.into()
    }
}

derive_prost_message_from_repr_bytes!(TxOutMembershipHash);

/// A hash of the shared secret used to confirm tx was sent
#[derive(
    Clone, Deserialize, Default, Eq, Ord, PartialEq, PartialOrd, Serialize, Debug, Digestible,
)]
pub struct TxOutConfirmationNumber([u8; 32]);

impl TxOutConfirmationNumber {
    /// Copies self into a new Vec.
    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }

    pub fn validate(
        &self,
        tx_pubkey: &RistrettoPublic,
        view_private_key: &RistrettoPrivate,
    ) -> bool {
        let shared_secret = get_tx_out_shared_secret(view_private_key, tx_pubkey);
        let calculated_confirmation = TxOutConfirmationNumber::from(&shared_secret);
        calculated_confirmation == *self
    }
}

impl core::convert::AsRef<[u8; 32]> for TxOutConfirmationNumber {
    #[inline]
    fn as_ref(&self) -> &[u8; 32] {
        &self.0
    }
}

impl core::convert::From<&[u8; 32]> for TxOutConfirmationNumber {
    #[inline]
    fn from(src: &[u8; 32]) -> Self {
        Self(*src)
    }
}

impl core::convert::From<[u8; 32]> for TxOutConfirmationNumber {
    #[inline]
    fn from(src: [u8; 32]) -> Self {
        Self(src)
    }
}

impl core::convert::From<&RistrettoPublic> for TxOutConfirmationNumber {
    fn from(shared_secret: &RistrettoPublic) -> Self {
        let mut hasher = Blake2b256::new();
        hasher.update(&TXOUT_CONFIRMATION_NUMBER_DOMAIN_TAG);
        hasher.update(shared_secret.to_bytes());

        let result: [u8; 32] = hasher.result().into();
        Self(result)
    }
}

impl ReprBytes for TxOutConfirmationNumber {
    type Error = &'static str;
    type Size = U32;
    fn from_bytes(src: &GenericArray<u8, U32>) -> Result<Self, &'static str> {
        Ok(Self((*src).into()))
    }
    fn to_bytes(&self) -> GenericArray<u8, U32> {
        self.0.into()
    }
}

derive_prost_message_from_repr_bytes!(TxOutConfirmationNumber);

#[cfg(test)]
mod tests {
    use crate::{
        encrypted_fog_hint::{EncryptedFogHint, ENCRYPTED_FOG_HINT_LEN},
        get_tx_out_shared_secret,
        memo::MemoPayload,
        ring_signature::SignatureRctBulletproofs,
        subaddress_matches_tx_out,
        tokens::Mob,
        tx::{Tx, TxIn, TxOut, TxPrefix},
        Amount, Token,
    };
    use alloc::vec::Vec;
    use mc_account_keys::{AccountKey, CHANGE_SUBADDRESS_INDEX, DEFAULT_SUBADDRESS_INDEX};
    use mc_crypto_keys::{RistrettoPrivate, RistrettoPublic};
    use mc_util_from_random::FromRandom;
    use prost::Message;
    use rand::{rngs::StdRng, SeedableRng};
    use std::convert::TryFrom;

    #[test]
    // `serialize_tx` should create a Tx, encode/decode it, and compare
    fn test_serialize_tx_no_memo() {
        let mut rng: StdRng = SeedableRng::from_seed([1u8; 32]);
        let tx_out = {
            let shared_secret = RistrettoPublic::from_random(&mut rng);
            let target_key = RistrettoPublic::from_random(&mut rng).into();
            let public_key = RistrettoPublic::from_random(&mut rng).into();
            let amount = Amount::new(23u64, &shared_secret).unwrap();
            TxOut {
                amount,
                target_key,
                public_key,
                e_fog_hint: EncryptedFogHint::from(&[1u8; ENCRYPTED_FOG_HINT_LEN]),
                e_memo: Default::default(),
            }
        };

        // TxOut = decode(encode(TxOut))
        let mut buf = Vec::new();
        tx_out.encode(&mut buf).expect("failed to serialize TxOut");
        assert_eq!(tx_out, TxOut::decode(&buf[..]).unwrap());

        let tx_in = TxIn {
            ring: vec![tx_out.clone()],
            proofs: vec![],
        };

        // TxIn = decode(encode(TxIn))
        let mut buf = Vec::new();
        tx_in.encode(&mut buf).expect("failed to serialize TxIn");
        assert_eq!(tx_in, TxIn::decode(&buf[..]).unwrap());

        let prefix = TxPrefix {
            inputs: vec![tx_in],
            outputs: vec![tx_out],
            fee: Mob::MINIMUM_FEE,
            tombstone_block: 23,
        };

        let mut buf = Vec::new();
        prefix
            .encode(&mut buf)
            .expect("failed to serialize into slice");

        assert_eq!(prefix, TxPrefix::decode(&buf[..]).unwrap());

        // TODO: use a meaningful signature.


text:
use std::borrow::Cow;

mod grab;

pub use grab::*;

use chandler::{ChandlerError, DownloadError};

#[derive(Debug)]
pub enum CommandErrorKind {
    //Arguments,
    Config,
    Other,
    Network,
}

impl CommandErrorKind {
    pub fn exit_code(&self) -> i32 {
        match self {
            //Self::Arguments => 1,
            Self::Config => 2,
            Self::Other => 101,
            Self::Network => 102,
        }
    }
}

#[derive(Debug)]
pub struct CommandError {
    pub kind: CommandErrorKind,
    pub description: Cow<'static, str>,
}

impl CommandError {
    pub fn new<S: Into<Cow<'static, str>>>(kind: CommandErrorKind, description: S) -> CommandError {
        CommandError {
            kind,
            description: description.into(),
        }
    }
}

impl From<ChandlerError> for CommandError {
    fn from(error: ChandlerError) -> Self {
        match error {
            ChandlerError::CreateProject(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error creating project: {err}"))
            }
            ChandlerError::LoadProject(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error loading project: {err}"))
            }
            ChandlerError::OpenConfig(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error opening config file: {err}"))
            }
            ChandlerError::ReadConfig(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error reading config file: {err}"))
            }
            ChandlerError::ParseConfig(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error parsing configuration: {err}"))
            }
            ChandlerError::Config(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Configuration error: {err}"))
            }
            ChandlerError::OpenFile(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error opening file: {err}"))
            }
            ChandlerError::CreateFile(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error creating file: {err}"))
            }
            ChandlerError::ReadFile(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error reading file: {err}"))
            }
            ChandlerError::WriteFile(err) => {
                CommandError::new(CommandErrorKind::Config, format!("Error writing file: {err}"))
            }
            ChandlerError::Download(err) => match err {
                DownloadError::Http { code, description } => CommandError::new(
                    CommandErrorKind::Other,
                    format!("Download HTTP error: {code} {description}"),
                ),
                DownloadError::Network(err) => CommandError::new(CommandErrorKind::Network, err.to_string()),
                DownloadError::Other(err) => CommandError::new(CommandErrorKind::Other, err.to_string()),
            },
            ChandlerError::Other(err) => CommandError::new(CommandErrorKind::Other, err.to_string()),
        }
    }
}


text:
// Copyright 2016 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

//! The [chacha20-poly1305@openssh.com] AEAD-ish construct.
//!
//! This should only be used by SSH implementations. It has a similar, but
//! different API from `ring::aead` because the construct cannot use the same
//! API as `ring::aead` due to the way the construct handles the encrypted
//! packet length.
//!
//! The concatenation of a and b is denoted `a||b`. `K_1` and `K_2` are defined
//! in the [chacha20-poly1305@openssh.com] specification. `packet_length`,
//! `padding_length`, `payload`, and `random padding` are defined in
//! [RFC 4253]. The term `plaintext` is used as a shorthand for
//! `padding_length||payload||random padding`.
//!
//! [chacha20-poly1305@openssh.com]:
//!    http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.chacha20poly1305?annotate=HEAD
//! [RFC 4253]: https://tools.ietf.org/html/rfc4253

use super::{chacha, chacha20_poly1305::derive_poly1305_key, poly1305, Tag, NONCE_LEN};
use crate::{constant_time, endian::*, error, polyfill::convert::*};

/// A key for sealing packets.
pub struct SealingKey {
    key: Key,
}

impl SealingKey {
    /// Constructs a new `SealingKey`.
    pub fn new(key_material: &[u8; KEY_LEN]) -> SealingKey {
        SealingKey {
            key: Key::new(key_material),
        }
    }

    /// Seals (encrypts and signs) a packet.
    ///
    /// On input, `plaintext_in_ciphertext_out` must contain the unencrypted
    /// `packet_length||plaintext` where `plaintext` is the
    /// `padding_length||payload||random padding`. It will be overwritten by
    /// `encrypted_packet_length||ciphertext`, where `encrypted_packet_length`
    /// is encrypted with `K_1` and `ciphertext` is encrypted by `K_2`.
    pub fn seal_in_place(
        &self, sequence_number: u32, plaintext_in_ciphertext_out: &mut [u8],
        tag_out: &mut [u8; TAG_LEN],
    ) {
        let mut counter = make_counter(sequence_number);

        {
            let (len_in_out, data_and_padding_in_out) =
                plaintext_in_ciphertext_out.split_at_mut(PACKET_LENGTH_LEN);

            chacha::chacha20_xor_in_place(&self.key.k_1, &counter, len_in_out);

            counter[0] = 1;
            chacha::chacha20_xor_in_place(&self.key.k_2, &counter, data_and_padding_in_out);
        }

        counter[0] = 0;
        let poly_key = derive_poly1305_key(&self.key.k_2, &counter);
        let Tag(tag) = poly1305::sign(poly_key, plaintext_in_ciphertext_out);
        tag_out.copy_from_slice(tag.as_ref());
    }
}

/// A key for opening packets.
pub struct OpeningKey {
    key: Key,
}

impl OpeningKey {
    /// Constructs a new `OpeningKey`.
    pub fn new(key_material: &[u8; KEY_LEN]) -> OpeningKey {
        OpeningKey {
            key: Key::new(key_material),
        }
    }

    /// Returns the decrypted, but unauthenticated, packet length.
    ///
    /// Importantly, the result won't be authenticated until `open_in_place` is
    /// called.
    pub fn decrypt_packet_length(
        &self, sequence_number: u32, encrypted_packet_length: [u8; PACKET_LENGTH_LEN],
    ) -> [u8; PACKET_LENGTH_LEN] {
        let mut packet_length = encrypted_packet_length;
        let counter = make_counter(sequence_number);
        chacha::chacha20_xor_in_place(&self.key.k_1, &counter, &mut packet_length);
        packet_length
    }

    /// Opens (authenticates and decrypts) a packet.
    ///
    /// `ciphertext_in_plaintext_out` must be of the form
    /// `encrypted_packet_length||ciphertext` where `ciphertext` is the
    /// encrypted `plaintext`. When the function succeeds the ciphertext is
    /// replaced by the plaintext and the result is `Ok(plaintext)`, where
    /// `plaintext` is `&ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..]`;
    /// otherwise the contents of `ciphertext_in_plaintext_out` are unspecified
    /// and must not be used.
    pub fn open_in_place<'a>(
        &self, sequence_number: u32, ciphertext_in_plaintext_out: &'a mut [u8], tag: &[u8; TAG_LEN],
    ) -> Result<&'a [u8], error::Unspecified> {
        let mut counter = make_counter(sequence_number);

        // We must verify the tag before decrypting so that
        // `ciphertext_in_plaintext_out` is unmodified if verification fails.
        // This is beyond what we guarantee.
        let poly_key = derive_poly1305_key(&self.key.k_2, &counter);
        verify(poly_key, ciphertext_in_plaintext_out, tag)?;

        let plaintext_in_ciphertext_out = &mut ciphertext_in_plaintext_out[PACKET_LENGTH_LEN..];
        counter[0] = 1;
        chacha::chacha20_xor_in_place(&self.key.k_2, &counter, plaintext_in_ciphertext_out);

        Ok(plaintext_in_ciphertext_out)
    }
}

struct Key {
    k_1: chacha::Key,
    k_2: chacha::Key,
}

impl Key {
    pub fn new(key_material: &[u8; KEY_LEN]) -> Key {
        // The first half becomes K_2 and the second half becomes K_1.
        let (k_2, k_1) = key_material.into_();
        Key {
            k_1: chacha::Key::from(k_1),
            k_2: chacha::Key::from(k_2),
        }
    }
}

fn make_counter(sequence_number: u32) -> chacha::Counter {
    let nonce = [
        BigEndian::ZERO,
        BigEndian::ZERO,
        BigEndian::from(sequence_number),
    ];
    let nonce: &[u8; NONCE_LEN] = as_bytes(&nonce).try_into_().unwrap();
    chacha::make_counter(nonce, 0)
}

/// The length of key.
pub const KEY_LEN: usize = chacha::KEY_LEN * 2;

/// The length in bytes of the `packet_length` field in a SSH packet.
pub const PACKET_LENGTH_LEN: usize = 4; // 32 bits

/// The length in bytes of an authentication tag.
pub const TAG_LEN: usize = super::BLOCK_LEN;

fn verify(key: poly1305::Key, msg: &[u8], tag: &[u8; TAG_LEN]) -> Result<(), error::Unspecified> {
    let Tag(calculated_tag) = poly1305::sign(key, msg);
    constant_time::verify_slices_are_equal(calculated_tag.as_ref(), tag)
}


text:
use std::cmp::{min, max};
use std::cmp::Ordering::{Less, Equal};
use std::convert::From;
use std::error::Error;
use std::fmt;
use std::iter::FusedIterator;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::option::Option::{Some, None};

use ipext::{IpAdd, IpSub, IpStep, IpAddrRange, Ipv4AddrRange, Ipv6AddrRange};

/// An IP network address, either IPv4 or IPv6.
///
/// This enum can contain either an [`Ipv4Net`] or an [`Ipv6Net`]. A
/// [`From`] implementation is provided to convert these into an
/// `IpNet`.
///
/// # Textual representation
///
/// `IpNet` provides a [`FromStr`] implementation for parsing network
/// addresses represented in CIDR notation. See [IETF RFC 4632] for the
/// CIDR notation.
///
/// [`Ipv4Net`]: struct.Ipv4Net.html
/// [`Ipv6Net`]: struct.Ipv6Net.html
/// [`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
/// [IETF RFC 4632]: https://tools.ietf.org/html/rfc4632
///
/// # Examples
///
/// ```
/// use std::net::IpAddr;
/// use ipnet::IpNet;
///
/// let net: IpNet = "10.1.1.0/24".parse().unwrap();
/// assert_eq!(Ok(net.network()), "10.1.1.0".parse());
///
/// let net: IpNet = "fd00::/32".parse().unwrap();
/// assert_eq!(Ok(net.network()), "fd00::".parse());
/// ```
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum IpNet {
    V4(Ipv4Net),
    V6(Ipv6Net),
}

/// An IPv4 network address.
///
/// See [`IpNet`] for a type encompassing both IPv4 and IPv6 network
/// addresses.
///
/// # Textual representation
///
/// `Ipv4Net` provides a [`FromStr`] implementation for parsing network
/// addresses represented in CIDR notation. See [IETF RFC 4632] for the
/// CIDR notation.
///
/// [`IpNet`]: enum.IpAddr.html
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
/// [IETF RFC 4632]: https://tools.ietf.org/html/rfc4632
///
/// # Examples
///
/// ```
/// use std::net::Ipv4Addr;
/// use ipnet::Ipv4Net;
///
/// let net: Ipv4Net = "10.1.1.0/24".parse().unwrap();
/// assert_eq!(Ok(net.network()), "10.1.1.0".parse());
/// ```
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ipv4Net {
    addr: Ipv4Addr,
    prefix_len: u8,
}

/// An IPv6 network address.
///
/// See [`IpNet`] for a type encompassing both IPv4 and IPv6 network
/// addresses.
///
/// # Textual representation
///
/// `Ipv6Net` provides a [`FromStr`] implementation for parsing network
/// addresses represented in CIDR notation. See [IETF RFC 4632] for the
/// CIDR notation.
///
/// [`IpNet`]: enum.IpAddr.html
/// [`FromStr`]: https://doc.rust-lang.org/std/str/trait.FromStr.html
/// [IETF RFC 4632]: https://tools.ietf.org/html/rfc4632
///
/// # Examples
///
/// ```
/// use std::net::Ipv6Addr;
/// use ipnet::Ipv6Net;
///
/// let net: Ipv6Net = "fd00::/32".parse().unwrap();
/// assert_eq!(Ok(net.network()), "fd00::".parse());
/// ```
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Ipv6Net {
    addr: Ipv6Addr,
    prefix_len: u8,
}

/// An error which can be returned when the prefix length is invalid.
///
/// Valid prefix lengths are 0 to 32 for IPv4 and 0 to 128 for IPv6.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PrefixLenError;

impl fmt::Display for PrefixLenError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt.write_str(self.description())
    }
}

impl Error for PrefixLenError {
    fn description(&self) -> &str {
        "invalid IP prefix length"
    }
}

impl IpNet {
    /// Returns a copy of the network with the address truncated to the
    /// prefix length.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::IpNet;
    /// #
    /// assert_eq!(
    ///     "192.168.12.34/16".parse::<IpNet>().unwrap().trunc(),
    ///     "192.168.0.0/16".parse().unwrap()
    /// );
    ///
    /// assert_eq!(
    ///     "fd00::1:2:3:4/16".parse::<IpNet>().unwrap().trunc(),
    ///     "fd00::/16".parse().unwrap()
    /// );
    /// ```
    pub fn trunc(&self) -> IpNet {
        match *self {
            IpNet::V4(ref a) => IpNet::V4(a.trunc()),
            IpNet::V6(ref a) => IpNet::V6(a.trunc()),
        }
    }

    /// Returns the address.
    pub fn addr(&self) -> IpAddr {
        match *self {
            IpNet::V4(ref a) => IpAddr::V4(a.addr),
            IpNet::V6(ref a) => IpAddr::V6(a.addr),
        }
    }

    /// Returns the prefix length.
    pub fn prefix_len(&self) -> u8 {
        match *self {
            IpNet::V4(ref a) => a.prefix_len(),
            IpNet::V6(ref a) => a.prefix_len(),
        }
    }

    /// Returns the maximum valid prefix length.
    pub fn max_prefix_len(&self) -> u8 {
        match *self {
            IpNet::V4(ref a) => a.max_prefix_len(),
            IpNet::V6(ref a) => a.max_prefix_len(),
        }
    }

    /// Returns the network mask.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::IpAddr;
    /// # use ipnet::IpNet;
    /// #
    /// let net: IpNet = "10.1.0.0/20".parse().unwrap();
    /// assert_eq!(Ok(net.netmask()), "255.255.240.0".parse());
    ///
    /// let net: IpNet = "fd00::/24".parse().unwrap();
    /// assert_eq!(Ok(net.netmask()), "ffff:ff00::".parse());
    /// ```
    pub fn netmask(&self) -> IpAddr {
        match *self {
            IpNet::V4(ref a) => IpAddr::V4(a.netmask()),
            IpNet::V6(ref a) => IpAddr::V6(a.netmask()),
        }
    }

    /// Returns the host mask.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::IpAddr;
    /// # use ipnet::IpNet;
    /// #
    /// let net: IpNet = "10.1.0.0/20".parse().unwrap();
    /// assert_eq!(Ok(net.hostmask()), "0.0.15.255".parse());
    ///
    /// let net: IpNet = "fd00::/24".parse().unwrap();
    /// assert_eq!(Ok(net.hostmask()), "::ff:ffff:ffff:ffff:ffff:ffff:ffff".parse());
    /// ```
    pub fn hostmask(&self) -> IpAddr {
        match *self {
            IpNet::V4(ref a) => IpAddr::V4(a.hostmask()),
            IpNet::V6(ref a) => IpAddr::V6(a.hostmask()),
        }
    }

    /// Returns the network address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::IpAddr;
    /// # use ipnet::IpNet;
    /// #
    /// let net: IpNet = "172.16.123.123/16".parse().unwrap();
    /// assert_eq!(Ok(net.network()), "172.16.0.0".parse());
    ///
    /// let net: IpNet = "fd00:1234:5678::/24".parse().unwrap();
    /// assert_eq!(Ok(net.network()), "fd00:1200::".parse());
    /// ```
    pub fn network(&self) -> IpAddr {
        match *self {
            IpNet::V4(ref a) => IpAddr::V4(a.network()),
            IpNet::V6(ref a) => IpAddr::V6(a.network()),
        }
    }

    /// Returns the broadcast address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::IpAddr;
    /// # use ipnet::IpNet;
    /// #
    /// let net: IpNet = "172.16.0.0/22".parse().unwrap();
    /// assert_eq!(Ok(net.broadcast()), "172.16.3.255".parse());
    ///
    /// let net: IpNet = "fd00:1234:5678::/24".parse().unwrap();
    /// assert_eq!(Ok(net.broadcast()), "fd00:12ff:ffff:ffff:ffff:ffff:ffff:ffff".parse());
    /// ```
    pub fn broadcast(&self) -> IpAddr {
        match *self {
            IpNet::V4(ref a) => IpAddr::V4(a.broadcast()),
            IpNet::V6(ref a) => IpAddr::V6(a.broadcast()),
        }
    }

    /// Returns the `IpNet` that contains this one.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::IpNet;
    /// #
    /// let n1: IpNet = "172.16.1.0/24".parse().unwrap();
    /// let n2: IpNet = "172.16.0.0/23".parse().unwrap();
    /// let n3: IpNet = "172.16.0.0/0".parse().unwrap();
    ///
    /// assert_eq!(n1.supernet().unwrap(), n2);
    /// assert_eq!(n3.supernet(), None);
    ///
    /// let n1: IpNet = "fd00:ff00::/24".parse().unwrap();
    /// let n2: IpNet = "fd00:fe00::/23".parse().unwrap();
    /// let n3: IpNet = "fd00:fe00::/0".parse().unwrap();
    ///
    /// assert_eq!(n1.supernet().unwrap(), n2);
    /// assert_eq!(n3.supernet(), None);
    /// ```
    pub fn supernet(&self) -> Option<IpNet> {
        match *self {
            IpNet::V4(ref a) => a.supernet().map(IpNet::V4),
            IpNet::V6(ref a) => a.supernet().map(IpNet::V6),
        }
    }

    /// Returns `true` if this network and the given network are
    /// children of the same supernet.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::IpNet;
    /// #
    /// let n4_1: IpNet = "10.1.0.0/24".parse().unwrap();
    /// let n4_2: IpNet = "10.1.1.0/24".parse().unwrap();
    /// let n4_3: IpNet = "10.1.2.0/24".parse().unwrap();
    /// let n6_1: IpNet = "fd00::/18".parse().unwrap();
    /// let n6_2: IpNet = "fd00:4000::/18".parse().unwrap();
    /// let n6_3: IpNet = "fd00:8000::/18".parse().unwrap();
    ///
    /// assert!( n4_1.is_sibling(&n4_2));
    /// assert!(!n4_2.is_sibling(&n4_3));
    /// assert!( n6_1.is_sibling(&n6_2));
    /// assert!(!n6_2.is_sibling(&n6_3));
    /// assert!(!n4_1.is_sibling(&n6_2));
    /// ```
    pub fn is_sibling(&self, other: &IpNet) -> bool {
        match (*self, *other) {
            (IpNet::V4(ref a), IpNet::V4(ref b)) => a.is_sibling(b),
            (IpNet::V6(ref a), IpNet::V6(ref b)) => a.is_sibling(b),
            _ => false,
        }
    }

    /// Return an `Iterator` over the host addresses in this network.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::IpAddr;
    /// # use ipnet::IpNet;
    /// #
    /// let net: IpNet = "10.0.0.0/30".parse().unwrap();
    /// assert_eq!(net.hosts().collect::<Vec<IpAddr>>(), vec![
    ///     "10.0.0.1".parse::<IpAddr>().unwrap(),
    ///     "10.0.0.2".parse().unwrap(),
    /// ]);
    ///
    /// let net: IpNet = "10.0.0.0/31".parse().unwrap();
    /// assert_eq!(net.hosts().collect::<Vec<IpAddr>>(), vec![
    ///     "10.0.0.0".parse::<IpAddr>().unwrap(),
    ///     "10.0.0.1".parse().unwrap(),
    /// ]);
    ///
    /// let net: IpNet = "fd00::/126".parse().unwrap();
    /// assert_eq!(net.hosts().collect::<Vec<IpAddr>>(), vec![
    ///     "fd00::".parse::<IpAddr>().unwrap(),
    ///     "fd00::1".parse().unwrap(),
    ///     "fd00::2".parse().unwrap(),
    ///     "fd00::3".parse().unwrap(),
    /// ]);
    /// ```
    pub fn hosts(&self) -> IpAddrRange {
        match *self {
            IpNet::V4(ref a) => IpAddrRange::V4(a.hosts()),
            IpNet::V6(ref a) => IpAddrRange::V6(a.hosts()),
        }
    }

    /// Returns an `Iterator` over the subnets of this network with the
    /// given prefix length.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::{IpNet, PrefixLenError};
    /// #
    /// let net: IpNet = "10.0.0.0/24".parse().unwrap();
    /// assert_eq!(net.subnets(26).unwrap().collect::<Vec<IpNet>>(), vec![
    ///     "10.0.0.0/26".parse::<IpNet>().unwrap(),
    ///     "10.0.0.64/26".parse().unwrap(),
    ///     "10.0.0.128/26".parse().unwrap(),
    ///     "10.0.0.192/26".parse().unwrap(),
    /// ]);
    ///
    /// let net: IpNet = "fd00::/16".parse().unwrap();
    /// assert_eq!(net.subnets(18).unwrap().collect::<Vec<IpNet>>(), vec![
    ///     "fd00::/18".parse::<IpNet>().unwrap(),
    ///     "fd00:4000::/18".parse().unwrap(),
    ///     "fd00:8000::/18".parse().unwrap(),
    ///     "fd00:c000::/18".parse().unwrap(),
    /// ]);
    ///
    /// let net: IpNet = "10.0.0.0/24".parse().unwrap();
    /// assert_eq!(net.subnets(23), Err(PrefixLenError));
    ///
    /// let net: IpNet = "10.0.0.0/24".parse().unwrap();
    /// assert_eq!(net.subnets(33), Err(PrefixLenError));
    ///
    /// let net: IpNet = "fd00::/16".parse().unwrap();
    /// assert_eq!(net.subnets(15), Err(PrefixLenError));
    ///
    /// let net: IpNet = "fd00::/16".parse().unwrap();
    /// assert_eq!(net.subnets(129), Err(PrefixLenError));
    /// ```
    pub fn subnets(&self, new_prefix_len: u8) -> Result<IpSubnets, PrefixLenError> {
        match *self {
            IpNet::V4(ref a) => a.subnets(new_prefix_len).map(IpSubnets::V4),
            IpNet::V6(ref a) => a.subnets(new_prefix_len).map(IpSubnets::V6),
        }
    }

    /// Test if a network address contains either another network
    /// address or an IP address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::IpAddr;
    /// # use ipnet::IpNet;
    /// #
    /// let net4: IpNet = "192.168.0.0/24".parse().unwrap();
    /// let net4_yes: IpNet = "192.168.0.0/25".parse().unwrap();
    /// let net4_no: IpNet = "192.168.0.0/23".parse().unwrap();
    /// let ip4_yes: IpAddr = "192.168.0.1".parse().unwrap();
    /// let ip4_no: IpAddr = "192.168.1.0".parse().unwrap();
    ///
    /// assert!(net4.contains(&net4));
    /// assert!(net4.contains(&net4_yes));
    /// assert!(!net4.contains(&net4_no));
    /// assert!(net4.contains(&ip4_yes));
    /// assert!(!net4.contains(&ip4_no));
    ///
    ///
    /// let net6: IpNet = "fd00::/16".parse().unwrap();
    /// let net6_yes: IpNet = "fd00::/17".parse().unwrap();
    /// let net6_no: IpNet = "fd00::/15".parse().unwrap();
    /// let ip6_yes: IpAddr = "fd00::1".parse().unwrap();
    /// let ip6_no: IpAddr = "fd01::".parse().unwrap();
    ///
    /// assert!(net6.contains(&net6));
    /// assert!(net6.contains(&net6_yes));
    /// assert!(!net6.contains(&net6_no));
    /// assert!(net6.contains(&ip6_yes));
    /// assert!(!net6.contains(&ip6_no));
    ///
    /// assert!(!net4.contains(&net6));
    /// assert!(!net6.contains(&net4));
    /// assert!(!net4.contains(&ip6_no));
    /// assert!(!net6.contains(&ip4_no));
    /// ```
    pub fn contains<T>(&self, other: T) -> bool where Self: Contains<T> {
        Contains::contains(self, other)
    }

    /// Aggregate a `Vec` of `IpNet`s and return the result as a new
    /// `Vec`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::IpNet;
    /// #
    /// let nets = vec![
    ///     "10.0.0.0/24".parse::<IpNet>().unwrap(),
    ///     "10.0.1.0/24".parse().unwrap(),
    ///     "10.0.2.0/24".parse().unwrap(),
    ///     "fd00::/18".parse().unwrap(),
    ///     "fd00:4000::/18".parse().unwrap(),
    ///     "fd00:8000::/18".parse().unwrap(),
    /// ];
    ///
    /// assert_eq!(IpNet::aggregate(&nets), vec![
    ///     "10.0.0.0/23".parse::<IpNet>().unwrap(),
    ///     "10.0.2.0/24".parse().unwrap(),
    ///     "fd00::/17".parse().unwrap(),
    ///     "fd00:8000::/18".parse().unwrap(),
    /// ]);
    /// ```
    pub fn aggregate(networks: &Vec<IpNet>) -> Vec<IpNet> {
        // It's 2.5x faster to split the input up and run them using the
        // specific IPv4 and IPV6 implementations. merge_intervals() and
        // the comparisons are much faster running over integers.
        let mut ipv4nets: Vec<Ipv4Net> = Vec::new();
        let mut ipv6nets: Vec<Ipv6Net> = Vec::new();

        for n in networks {
            match *n {
                IpNet::V4(x) => ipv4nets.push(x),
                IpNet::V6(x) => ipv6nets.push(x),
            }
        }

        let mut res: Vec<IpNet> = Vec::new();
        let ipv4aggs = Ipv4Net::aggregate(&ipv4nets);
        let ipv6aggs = Ipv6Net::aggregate(&ipv6nets);
        res.extend::<Vec<IpNet>>(ipv4aggs.into_iter().map(IpNet::V4).collect::<Vec<IpNet>>());
        res.extend::<Vec<IpNet>>(ipv6aggs.into_iter().map(IpNet::V6).collect::<Vec<IpNet>>());
        res
    }
}

impl Default for IpNet {
    fn default() -> Self {
        Self::V4(Ipv4Net::default())
    }
}

impl fmt::Debug for IpNet {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self, fmt)
    }
}

impl fmt::Display for IpNet {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IpNet::V4(ref a) => a.fmt(fmt),
            IpNet::V6(ref a) => a.fmt(fmt),
        }
    }
}

impl From<Ipv4Net> for IpNet {
    fn from(net: Ipv4Net) -> IpNet {
        IpNet::V4(net)
    }
}

impl From<Ipv6Net> for IpNet {
    fn from(net: Ipv6Net) -> IpNet {
        IpNet::V6(net)
    }
}

impl From<IpAddr> for IpNet {
    fn from(addr: IpAddr) -> IpNet {
        match addr {
            IpAddr::V4(a) => IpNet::V4(a.into()),
            IpAddr::V6(a) => IpNet::V6(a.into()),
        }
    }
}

impl Ipv4Net {
    /// Creates a new IPv4 network address from an `Ipv4Addr` and prefix
    /// length.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv4Addr;
    /// use ipnet::{Ipv4Net, PrefixLenError};
    ///
    /// let net = Ipv4Net::new(Ipv4Addr::new(10, 1, 1, 0), 24);
    /// assert!(net.is_ok());
    ///
    /// let bad_prefix_len = Ipv4Net::new(Ipv4Addr::new(10, 1, 1, 0), 33);
    /// assert_eq!(bad_prefix_len, Err(PrefixLenError));
    /// ```
    pub fn new(ip: Ipv4Addr, prefix_len: u8) -> Result<Ipv4Net, PrefixLenError> {
        if prefix_len > 32 {
            return Err(PrefixLenError);
        }
        Ok(Ipv4Net { addr: ip, prefix_len: prefix_len })
    }

    /// Returns a copy of the network with the address truncated to the
    /// prefix length.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::Ipv4Net;
    /// #
    /// assert_eq!(
    ///     "192.168.12.34/16".parse::<Ipv4Net>().unwrap().trunc(),
    ///     "192.168.0.0/16".parse().unwrap()
    /// );
    /// ```
    pub fn trunc(&self) -> Ipv4Net {
        Ipv4Net::new(self.network(), self.prefix_len).unwrap()
    }

    /// Returns the address.
    pub fn addr(&self) -> Ipv4Addr {
        self.addr
    }

    /// Returns the prefix length.
    pub fn prefix_len(&self) -> u8 {
        self.prefix_len
    }

    /// Returns the maximum valid prefix length.
    pub fn max_prefix_len(&self) -> u8 {
        32
    }

    /// Returns the network mask.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::Ipv4Addr;
    /// # use ipnet::Ipv4Net;
    /// #
    /// let net: Ipv4Net = "10.1.0.0/20".parse().unwrap();
    /// assert_eq!(Ok(net.netmask()), "255.255.240.0".parse());
    /// ```
    pub fn netmask(&self) -> Ipv4Addr {
        Ipv4Addr::from(self.netmask_u32())
    }

    fn netmask_u32(&self) -> u32 {
        u32::max_value().checked_shl(32 - self.prefix_len as u32).unwrap_or(0)
    }

    /// Returns the host mask.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::Ipv4Addr;
    /// # use ipnet::Ipv4Net;
    /// #
    /// let net: Ipv4Net = "10.1.0.0/20".parse().unwrap();
    /// assert_eq!(Ok(net.hostmask()), "0.0.15.255".parse());
    /// ```
    pub fn hostmask(&self) -> Ipv4Addr {
        Ipv4Addr::from(self.hostmask_u32())
    }

    fn hostmask_u32(&self) -> u32 {
        u32::max_value().checked_shr(self.prefix_len as u32).unwrap_or(0)
    }

    /// Returns the network address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::Ipv4Addr;
    /// # use ipnet::Ipv4Net;
    /// #
    /// let net: Ipv4Net = "172.16.123.123/16".parse().unwrap();
    /// assert_eq!(Ok(net.network()), "172.16.0.0".parse());
    /// ```
    pub fn network(&self) -> Ipv4Addr {
        Ipv4Addr::from(u32::from(self.addr) & self.netmask_u32())
    }

    /// Returns the broadcast address.
    ///
    /// # Examples
    ///
    /// ```
    /// # use std::net::Ipv4Addr;
    /// # use ipnet::Ipv4Net;
    /// #
    /// let net: Ipv4Net = "172.16.0.0/22".parse().unwrap();
    /// assert_eq!(Ok(net.broadcast()), "172.16.3.255".parse());
    /// ```
    pub fn broadcast(&self) -> Ipv4Addr {
        Ipv4Addr::from(u32::from(self.addr) | self.hostmask_u32())
    }

    /// Returns the `Ipv4Net` that contains this one.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ipnet::Ipv4Net;
    /// #
    /// let n1: Ipv4Net = "172.16.1.0/24".parse().unwrap();
    /// let n2: Ipv4Net = "172.16.0.0/23".parse().unwrap();
    /// let n3: Ipv4Net = "172.16.0.0/0".parse().unwrap();
    ///
    /// assert_eq!(n1.supernet().unwrap(), n2);
    /// assert_eq!(n3.supernet(), None);
    /// ```
    pub fn supernet(&self) -> Option<Ipv4Net> {
        Ipv4Net::new(self.addr, self.prefix_len.wrapping_sub(1)).map(|n| n.trunc()).ok()


text:
use async_trait::async_trait;
use futures::channel::mpsc::UnboundedSender as Sender;

use crate::{
    gateway::InterMessage,
    model::{
        id::{GuildId, UserId},
        voice::VoiceState,
    },
};

/// Interface for any compatible voice plugin.
///
/// This interface covers several serenity-specific hooks, as well as
/// packet handlers for voice-specific gateway messages.
#[async_trait]
pub trait VoiceGatewayManager: Send + Sync {
    /// Performs initial setup at the start of a connection to Discord.
    ///
    /// This will only occur once, and provides the bot's ID and shard count.
    async fn initialise(&self, shard_count: u64, user_id: UserId);

    /// Handler fired in response to a [`Ready`] event.
    ///
    /// This provides the voice plugin with a channel to send gateway messages to Discord,
    /// once per active shard.
    ///
    /// [`Ready`]: crate::model::event::Event
    async fn register_shard(&self, shard_id: u64, sender: Sender<InterMessage>);

    /// Handler fired in response to a disconnect, reconnection, or rebalance.
    ///
    /// This event invalidates the last sender associated with `shard_id`.
    /// Unless the bot is fully disconnecting, this is often followed by a call
    /// to [`Self::register_shard`]. Users may wish to buffer manually any gateway messages
    /// sent between these calls.
    async fn deregister_shard(&self, shard_id: u64);

    /// Handler for VOICE_SERVER_UPDATE messages.
    ///
    /// These contain the endpoint and token needed to form a voice connection session.
    async fn server_update(&self, guild_id: GuildId, endpoint: &Option<String>, token: &str);

    /// Handler for VOICE_STATE_UPDATE messages.
    ///
    /// These contain the session ID needed to form a voice connection session.
    async fn state_update(&self, guild_id: GuildId, voice_state: &VoiceState);
}


text:
use std::collections::HashMap;

use crate::internal::prelude::*;
use crate::model::guild::GuildWelcomeScreenEmoji;
use crate::utils;

/// A builder to specify the fields to edit in a [`GuildWelcomeScreen`].
///
/// [`GuildWelcomeScreen`]: crate::model::guild::GuildWelcomeScreen
#[derive(Clone, Debug, Default)]
pub struct EditGuildWelcomeScreen(pub HashMap<&'static str, Value>);

impl EditGuildWelcomeScreen {
    /// Whether the welcome screen is enabled or not.
    pub fn enabled(&mut self, enabled: bool) -> &mut Self {
        self.0.insert("enabled", Value::Bool(enabled));

        self
    }

    /// The server description shown in the welcome screen.
    pub fn description<D: ToString>(&mut self, description: D) -> &mut Self {
        self.0.insert("description", Value::String(description.to_string()));

        self
    }

    pub fn create_welcome_channel<F>(&mut self, f: F) -> &mut Self
    where
        F: FnOnce(&mut CreateGuildWelcomeChannel) -> &mut CreateGuildWelcomeChannel,
    {
        let mut data = CreateGuildWelcomeChannel::default();
        f(&mut data);

        self.add_welcome_channel(data);

        self
    }

    pub fn add_welcome_channel(&mut self, channel: CreateGuildWelcomeChannel) -> &mut Self {
        let new_data = utils::hashmap_to_json_map(channel.0);

        let channels = self.0.entry("welcome_channels").or_insert_with(|| Value::Array(Vec::new()));
        let channels_array = channels.as_array_mut().expect("Must be an array.");

        channels_array.push(Value::Object(new_data));

        self
    }

    pub fn set_welcome_channels(&mut self, channels: Vec<CreateGuildWelcomeChannel>) -> &mut Self {
        let new_channels = channels
            .into_iter()
            .map(|f| Value::Object(utils::hashmap_to_json_map(f.0)))
            .collect::<Vec<Value>>();

        self.0.insert("welcome_channels", Value::Array(new_channels));

        self
    }
}

/// A builder for creating a [`GuildWelcomeChannel`].
///
/// [`GuildWelcomeChannel`]: crate::model::guild::GuildWelcomeChannel
#[derive(Clone, Debug, Default)]
pub struct CreateGuildWelcomeChannel(pub HashMap<&'static str, Value>);

impl CreateGuildWelcomeChannel {
    /// The Id of the channel to show. It is required.
    pub fn id(&mut self, id: u64) -> &mut Self {
        self.0.insert("channel_id", Value::String(id.to_string()));

        self
    }

    /// The description shown for the channel. It is required.
    pub fn description<D: ToString>(&mut self, description: D) -> &mut Self {
        self.0.insert("description", Value::String(description.to_string()));

        self
    }

    /// The emoji shown for the channel.
    pub fn emoji(&mut self, emoji: GuildWelcomeScreenEmoji) -> &mut Self {
        match emoji {
            GuildWelcomeScreenEmoji::Unicode(name) => {
                self.0.insert("emoji_name", Value::String(name))
            },
            GuildWelcomeScreenEmoji::Custom(id) => {
                self.0.insert("emoji_id", Value::String(id.to_string()))
            },
        };

        self
    }
}