use std::default;
use std::error;
use std::fmt::{self, Write};
use std::ops;
use std::str::FromStr;
use std::cmp::Ordering;
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum Denomination {
    
    Bitcoin,
    
    MilliBitcoin,
    
    MicroBitcoin,
    
    Bit,
    
    Satoshi,
    
    MilliSatoshi,
}
impl Denomination {
    
    fn precision(self) -> i32 {
        match self {
            Denomination::Bitcoin => -8,
            Denomination::MilliBitcoin => -5,
            Denomination::MicroBitcoin => -2,
            Denomination::Bit => -2,
            Denomination::Satoshi => 0,
            Denomination::MilliSatoshi => 3,
        }
    }
}
impl fmt::Display for Denomination {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(match *self {
            Denomination::Bitcoin => "BTC",
            Denomination::MilliBitcoin => "mBTC",
            Denomination::MicroBitcoin => "uBTC",
            Denomination::Bit => "bits",
            Denomination::Satoshi => "satoshi",
            Denomination::MilliSatoshi => "msat",
        })
    }
}
impl FromStr for Denomination {
    type Err = ParseAmountError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "BTC" => Ok(Denomination::Bitcoin),
            "mBTC" => Ok(Denomination::MilliBitcoin),
            "uBTC" => Ok(Denomination::MicroBitcoin),
            "bits" => Ok(Denomination::Bit),
            "satoshi" => Ok(Denomination::Satoshi),
            "sat" => Ok(Denomination::Satoshi),
            "msat" => Ok(Denomination::MilliSatoshi),
            d => Err(ParseAmountError::UnknownDenomination(d.to_owned())),
        }
    }
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseAmountError {
    
    Negative,
    
    TooBig,
    
    TooPrecise,
    
    InvalidFormat,
    
    InputTooLarge,
    
    InvalidCharacter(char),
    
    UnknownDenomination(String),
}
impl fmt::Display for ParseAmountError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ParseAmountError::Negative => f.write_str("amount is negative"),
            ParseAmountError::TooBig => f.write_str("amount is too big"),
            ParseAmountError::TooPrecise => f.write_str("amount has a too high precision"),
            ParseAmountError::InvalidFormat => f.write_str("invalid number format"),
            ParseAmountError::InputTooLarge => f.write_str("input string was too large"),
            ParseAmountError::InvalidCharacter(c) => write!(f, "invalid character in input: {}", c),
            ParseAmountError::UnknownDenomination(ref d) => write!(f, "unknown denomination: {}",d),
        }
    }
}
impl error::Error for ParseAmountError {}
fn is_too_precise(s: &str, precision: usize) -> bool {
    s.contains('.') || precision >= s.len() || s.chars().rev().take(precision).any(|d| d != '0')
}
fn parse_signed_to_satoshi(
    mut s: &str,
    denom: Denomination,
) -> Result<(bool, u64), ParseAmountError> {
    if s.is_empty() {
        return Err(ParseAmountError::InvalidFormat);
    }
    if s.len() > 50 {
        return Err(ParseAmountError::InputTooLarge);
    }
    let is_negative = s.starts_with('-');
    if is_negative {
        if s.len() == 1 {
            return Err(ParseAmountError::InvalidFormat);
        }
        s = &s[1..];
    }
    let max_decimals = {
        
        
        let precision_diff = -denom.precision();
        if precision_diff < 0 {
            
            
            
            
            let last_n = precision_diff.abs() as usize;
            if is_too_precise(s, last_n) {
                return Err(ParseAmountError::TooPrecise);
            }
            s = &s[0..s.len() - last_n];
            0
        } else {
            precision_diff
        }
    };
    let mut decimals = None;
    let mut value: u64 = 0; 
    for c in s.chars() {
        match c {
            '0'..='9' => {
                
                match 10_u64.checked_mul(value) {
                    None => return Err(ParseAmountError::TooBig),
                    Some(val) => match val.checked_add((c as u8 - b'0') as u64) {
                        None => return Err(ParseAmountError::TooBig),
                        Some(val) => value = val,
                    },
                }
                
                decimals = match decimals {
                    None => None,
                    Some(d) if d < max_decimals => Some(d + 1),
                    _ => return Err(ParseAmountError::TooPrecise),
                };
            }
            '.' => match decimals {
                None => decimals = Some(0),
                
                _ => return Err(ParseAmountError::InvalidFormat),
            },
            c => return Err(ParseAmountError::InvalidCharacter(c)),
        }
    }
    
    let scale_factor = max_decimals - decimals.unwrap_or(0);
    for _ in 0..scale_factor {
        value = match 10_u64.checked_mul(value) {
            Some(v) => v,
            None => return Err(ParseAmountError::TooBig),
        };
    }
    Ok((is_negative, value))
}
fn fmt_satoshi_in(
    satoshi: u64,
    negative: bool,
    f: &mut dyn fmt::Write,
    denom: Denomination,
) -> fmt::Result {
    if negative {
        f.write_str("-")?;
    }
    let precision = denom.precision();
    match precision.cmp(&0) {
        Ordering::Greater => {
            
            let width = precision as usize;
            write!(f, "{}{:0width$}", satoshi, 0, width = width)?;
        }
        Ordering::Less => {
            
            let nb_decimals = precision.abs() as usize;
            let real = format!("{:0width$}", satoshi, width = nb_decimals);
            if real.len() == nb_decimals {
                write!(f, "0.{}", &real[real.len() - nb_decimals..])?;
            } else {
                write!(
                    f,
                    "{}.{}",
                    &real[0..(real.len() - nb_decimals)],
                    &real[real.len() - nb_decimals..]
                )?;
            }
        }
        Ordering::Equal => write!(f, "{}", satoshi)?,
    }
    Ok(())
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Amount(u64);
impl Amount {
    
    pub const ZERO: Amount = Amount(0);
    
    pub const ONE_SAT: Amount = Amount(1);
    
    pub const ONE_BTC: Amount = Amount(100_000_000);
    
    pub fn from_sat(satoshi: u64) -> Amount {
        Amount(satoshi)
    }
    
    pub fn as_sat(self) -> u64 {
        self.0
    }
    
    pub fn max_value() -> Amount {
        Amount(u64::max_value())
    }
    
    pub fn min_value() -> Amount {
        Amount(u64::min_value())
    }
    
    pub fn from_btc(btc: f64) -> Result<Amount, ParseAmountError> {
        Amount::from_float_in(btc, Denomination::Bitcoin)
    }
    
    
    
    
    pub fn from_str_in(s: &str, denom: Denomination) -> Result<Amount, ParseAmountError> {
        let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
        if negative {
            return Err(ParseAmountError::Negative);
        }
        if satoshi > i64::max_value() as u64 {
            return Err(ParseAmountError::TooBig);
        }
        Ok(Amount::from_sat(satoshi))
    }
    
    
    
    
    pub fn from_str_with_denomination(s: &str) -> Result<Amount, ParseAmountError> {
        let mut split = s.splitn(3, ' ');
        let amt_str = split.next().unwrap();
        let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?;
        if split.next().is_some() {
            return Err(ParseAmountError::InvalidFormat);
        }
        Ok(Amount::from_str_in(amt_str, denom_str.parse()?)?)
    }
    
    
    
    pub fn to_float_in(self, denom: Denomination) -> f64 {
        f64::from_str(&self.to_string_in(denom)).unwrap()
    }
    
    
    
    
    
    pub fn as_btc(self) -> f64 {
        self.to_float_in(Denomination::Bitcoin)
    }
    
    
    
    
    
    pub fn from_float_in(value: f64, denom: Denomination) -> Result<Amount, ParseAmountError> {
        if value < 0.0 {
            return Err(ParseAmountError::Negative);
        }
        
        
        Amount::from_str_in(&value.to_string(), denom)
    }
    
    
    
    pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
        fmt_satoshi_in(self.as_sat(), false, f, denom)
    }
    
    
    
    pub fn to_string_in(self, denom: Denomination) -> String {
        let mut buf = String::new();
        self.fmt_value_in(&mut buf, denom).unwrap();
        buf
    }
    
    
    pub fn to_string_with_denomination(self, denom: Denomination) -> String {
        let mut buf = String::new();
        self.fmt_value_in(&mut buf, denom).unwrap();
        write!(buf, " {}", denom).unwrap();
        buf
    }
    
    
    
    pub fn checked_add(self, rhs: Amount) -> Option<Amount> {
        self.0.checked_add(rhs.0).map(Amount)
    }
    
    
    pub fn checked_sub(self, rhs: Amount) -> Option<Amount> {
        self.0.checked_sub(rhs.0).map(Amount)
    }
    
    
    pub fn checked_mul(self, rhs: u64) -> Option<Amount> {
        self.0.checked_mul(rhs).map(Amount)
    }
    
    
    
    
    pub fn checked_div(self, rhs: u64) -> Option<Amount> {
        self.0.checked_div(rhs).map(Amount)
    }
    
    
    pub fn checked_rem(self, rhs: u64) -> Option<Amount> {
        self.0.checked_rem(rhs).map(Amount)
    }
    
    pub fn to_signed(self) -> Result<SignedAmount, ParseAmountError> {
        if self.as_sat() > SignedAmount::max_value().as_sat() as u64 {
            Err(ParseAmountError::TooBig)
        } else {
            Ok(SignedAmount::from_sat(self.as_sat() as i64))
        }
    }
}
impl default::Default for Amount {
    fn default() -> Self {
        Amount::ZERO
    }
}
impl fmt::Debug for Amount {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Amount({:.8} BTC)", self.as_btc())
    }
}
impl fmt::Display for Amount {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.fmt_value_in(f, Denomination::Bitcoin)?;
        write!(f, " {}", Denomination::Bitcoin)
    }
}
impl ops::Add for Amount {
    type Output = Amount;
    fn add(self, rhs: Amount) -> Self::Output {
        self.checked_add(rhs).expect("Amount addition error")
    }
}
impl ops::AddAssign for Amount {
    fn add_assign(&mut self, other: Amount) {
        *self = *self + other
    }
}
impl ops::Sub for Amount {
    type Output = Amount;
    fn sub(self, rhs: Amount) -> Self::Output {
        self.checked_sub(rhs).expect("Amount subtraction error")
    }
}
impl ops::SubAssign for Amount {
    fn sub_assign(&mut self, other: Amount) {
        *self = *self - other
    }
}
impl ops::Rem<u64> for Amount {
    type Output = Amount;
    fn rem(self, modulus: u64) -> Self {
        self.checked_rem(modulus).expect("Amount remainder error")
    }
}
impl ops::RemAssign<u64> for Amount {
    fn rem_assign(&mut self, modulus: u64) {
        *self = *self % modulus
    }
}
impl ops::Mul<u64> for Amount {
    type Output = Amount;
    fn mul(self, rhs: u64) -> Self::Output {
        self.checked_mul(rhs).expect("Amount multiplication error")
    }
}
impl ops::MulAssign<u64> for Amount {
    fn mul_assign(&mut self, rhs: u64) {
        *self = *self * rhs
    }
}
impl ops::Div<u64> for Amount {
    type Output = Amount;
    fn div(self, rhs: u64) -> Self::Output {
        self.checked_div(rhs).expect("Amount division error")
    }
}
impl ops::DivAssign<u64> for Amount {
    fn div_assign(&mut self, rhs: u64) {
        *self = *self / rhs
    }
}
impl FromStr for Amount {
    type Err = ParseAmountError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        Amount::from_str_with_denomination(s)
    }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SignedAmount(i64);
impl SignedAmount {
    
    pub const ZERO: SignedAmount = SignedAmount(0);
    
    pub const ONE_SAT: SignedAmount = SignedAmount(1);
    
    pub const ONE_BTC: SignedAmount = SignedAmount(100_000_000);
    
    pub fn from_sat(satoshi: i64) -> SignedAmount {
        SignedAmount(satoshi)
    }
    
    pub fn as_sat(self) -> i64 {
        self.0
    }
    
    pub fn max_value() -> SignedAmount {
        SignedAmount(i64::max_value())
    }
    
    pub fn min_value() -> SignedAmount {
        SignedAmount(i64::min_value())
    }
    
    pub fn from_btc(btc: f64) -> Result<SignedAmount, ParseAmountError> {
        SignedAmount::from_float_in(btc, Denomination::Bitcoin)
    }
    
    
    
    
    pub fn from_str_in(s: &str, denom: Denomination) -> Result<SignedAmount, ParseAmountError> {
        let (negative, satoshi) = parse_signed_to_satoshi(s, denom)?;
        if satoshi > i64::max_value() as u64 {
            return Err(ParseAmountError::TooBig);
        }
        Ok(match negative {
            true => SignedAmount(-(satoshi as i64)),
            false => SignedAmount(satoshi as i64),
        })
    }
    
    
    
    
    pub fn from_str_with_denomination(s: &str) -> Result<SignedAmount, ParseAmountError> {
        let mut split = s.splitn(3, ' ');
        let amt_str = split.next().unwrap();
        let denom_str = split.next().ok_or(ParseAmountError::InvalidFormat)?;
        if split.next().is_some() {
            return Err(ParseAmountError::InvalidFormat);
        }
        Ok(SignedAmount::from_str_in(amt_str, denom_str.parse()?)?)
    }
    
    
    
    pub fn to_float_in(self, denom: Denomination) -> f64 {
        f64::from_str(&self.to_string_in(denom)).unwrap()
    }
    
    
    
    
    
    pub fn as_btc(self) -> f64 {
        self.to_float_in(Denomination::Bitcoin)
    }
    
    
    
    
    
    pub fn from_float_in(
        value: f64,
        denom: Denomination,
    ) -> Result<SignedAmount, ParseAmountError> {
        
        
        SignedAmount::from_str_in(&value.to_string(), denom)
    }
    
    
    
    pub fn fmt_value_in(self, f: &mut dyn fmt::Write, denom: Denomination) -> fmt::Result {
        let sats = self.as_sat().checked_abs().map(|a: i64| a as u64).unwrap_or_else(|| {
            
            u64::max_value() - self.as_sat() as u64 +1
        });
        fmt_satoshi_in(sats, self.is_negative(), f, denom)
    }
    
    
    
    pub fn to_string_in(self, denom: Denomination) -> String {
        let mut buf = String::new();
        self.fmt_value_in(&mut buf, denom).unwrap();
        buf
    }
    
    
    pub fn to_string_with_denomination(self, denom: Denomination) -> String {
        let mut buf = String::new();
        self.fmt_value_in(&mut buf, denom).unwrap();
        write!(buf, " {}", denom).unwrap();
        buf
    }
    
    
    pub fn abs(self) -> SignedAmount {
        SignedAmount(self.0.abs())
    }
    
    
    
    
    
    pub fn signum(self) -> i64 {
        self.0.signum()
    }
    
    
    pub fn is_positive(self) -> bool {
        self.0.is_positive()
    }
    
    
    pub fn is_negative(self) -> bool {
        self.0.is_negative()
    }
    
    
    pub fn checked_abs(self) -> Option<SignedAmount> {
        self.0.checked_abs().map(SignedAmount)
    }
    
    
    pub fn checked_add(self, rhs: SignedAmount) -> Option<SignedAmount> {
        self.0.checked_add(rhs.0).map(SignedAmount)
    }
    
    
    pub fn checked_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
        self.0.checked_sub(rhs.0).map(SignedAmount)
    }
    
    
    pub fn checked_mul(self, rhs: i64) -> Option<SignedAmount> {
        self.0.checked_mul(rhs).map(SignedAmount)
    }
    
    
    
    
    pub fn checked_div(self, rhs: i64) -> Option<SignedAmount> {
        self.0.checked_div(rhs).map(SignedAmount)
    }
    
    
    pub fn checked_rem(self, rhs: i64) -> Option<SignedAmount> {
        self.0.checked_rem(rhs).map(SignedAmount)
    }
    
    
    pub fn positive_sub(self, rhs: SignedAmount) -> Option<SignedAmount> {
        if self.is_negative() || rhs.is_negative() || rhs > self {
            None
        } else {
            self.checked_sub(rhs)
        }
    }
    
    pub fn to_unsigned(self) -> Result<Amount, ParseAmountError> {
        if self.is_negative() {
            Err(ParseAmountError::Negative)
        } else {
            Ok(Amount::from_sat(self.as_sat() as u64))
        }
    }
}
impl default::Default for SignedAmount {
    fn default() -> Self {
        SignedAmount::ZERO
    }
}
impl fmt::Debug for SignedAmount {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "SignedAmount({:.8} BTC)", self.as_btc())
    }
}
impl fmt::Display for SignedAmount {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.fmt_value_in(f, Denomination::Bitcoin)?;
        write!(f, " {}", Denomination::Bitcoin)
    }
}
impl ops::Add for SignedAmount {
    type Output = SignedAmount;
    fn add(self, rhs: SignedAmount) -> Self::Output {
        self.checked_add(rhs).expect("SignedAmount addition error")
    }
}
impl ops::AddAssign for SignedAmount {
    fn add_assign(&mut self, other: SignedAmount) {
        *self = *self + other
    }
}
impl ops::Sub for SignedAmount {
    type Output = SignedAmount;
    fn sub(self, rhs: SignedAmount) -> Self::Output {
        self.checked_sub(rhs).expect("SignedAmount subtraction error")
    }
}
impl ops::SubAssign for SignedAmount {
    fn sub_assign(&mut self, other: SignedAmount) {
        *self = *self - other
    }
}
impl ops::Rem<i64> for SignedAmount {
    type Output = SignedAmount;
    fn rem(self, modulus: i64) -> Self {
        self.checked_rem(modulus).expect("SignedAmount remainder error")
    }
}
impl ops::RemAssign<i64> for SignedAmount {
    fn rem_assign(&mut self, modulus: i64) {
        *self = *self % modulus
    }
}
impl ops::Mul<i64> for SignedAmount {
    type Output = SignedAmount;
    fn mul(self, rhs: i64) -> Self::Output {
        self.checked_mul(rhs).expect("SignedAmount multiplication error")
    }
}
impl ops::MulAssign<i64> for SignedAmount {
    fn mul_assign(&mut self, rhs: i64) {
        *self = *self * rhs
    }
}
impl ops::Div<i64> for SignedAmount {
    type Output = SignedAmount;
    fn div(self, rhs: i64) -> Self::Output {
        self.checked_div(rhs).expect("SignedAmount division error")
    }
}
impl ops::DivAssign<i64> for SignedAmount {
    fn div_assign(&mut self, rhs: i64) {
        *self = *self / rhs
    }
}
impl FromStr for SignedAmount {
    type Err = ParseAmountError;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        SignedAmount::from_str_with_denomination(s)
    }
}
#[cfg(feature = "serde")]
pub mod serde {
    
    #![allow(missing_docs)]
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    use serde::{Deserialize, Deserializer, Serialize, Serializer};
    use util::amount::{Amount, Denomination, SignedAmount};
    
    
    
    
    pub trait SerdeAmount: Copy + Sized {
        fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
        fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
        fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
        fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error>;
    }
    mod private {
        
        
        pub trait Sealed {}
        impl Sealed for super::Amount {}
        impl Sealed for super::SignedAmount {}
    }
    
    pub trait SerdeAmountForOpt: Copy + Sized + SerdeAmount + private::Sealed {
        fn type_prefix() -> &'static str;
        fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
        fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error>;
    }
    impl SerdeAmount for Amount {
        fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            u64::serialize(&self.as_sat(), s)
        }
        fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
            Ok(Amount::from_sat(u64::deserialize(d)?))
        }
        fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
        }
        fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
            use serde::de::Error;
            Ok(Amount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
        }
    }
    impl SerdeAmountForOpt for Amount {
        fn type_prefix() -> &'static str {
            "u"
        }
        fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            s.serialize_some(&self.as_sat())
        }
        fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            s.serialize_some(&self.as_btc())
        }
    }
    impl SerdeAmount for SignedAmount {
        fn ser_sat<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            i64::serialize(&self.as_sat(), s)
        }
        fn des_sat<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
            Ok(SignedAmount::from_sat(i64::deserialize(d)?))
        }
        fn ser_btc<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            f64::serialize(&self.to_float_in(Denomination::Bitcoin), s)
        }
        fn des_btc<'d, D: Deserializer<'d>>(d: D) -> Result<Self, D::Error> {
            use serde::de::Error;
            Ok(SignedAmount::from_btc(f64::deserialize(d)?).map_err(D::Error::custom)?)
        }
    }
    impl SerdeAmountForOpt for SignedAmount {
        fn type_prefix() -> &'static str {
            "i"
        }
        fn ser_sat_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            s.serialize_some(&self.as_sat())
        }
        fn ser_btc_opt<S: Serializer>(self, s: S) -> Result<S::Ok, S::Error> {
            s.serialize_some(&self.as_btc())
        }
    }
    pub mod as_sat {
        
        
        use serde::{Deserializer, Serializer};
        use util::amount::serde::SerdeAmount;
        pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
            a.ser_sat(s)
        }
        pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
            A::des_sat(d)
        }
        pub mod opt {
            
            
            use serde::{Deserializer, Serializer, de};
            use util::amount::serde::SerdeAmountForOpt;
            use std::fmt;
            use std::marker::PhantomData;
            pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
                a: &Option<A>,
                s: S,
            ) -> Result<S::Ok, S::Error> {
                match *a {
                    Some(a) => a.ser_sat_opt(s),
                    None => s.serialize_none(),
                }
            }
            pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>(
                d: D,
            ) -> Result<Option<A>, D::Error> {
                struct VisitOptAmt<X>(PhantomData<X>);
                impl<'de, X: SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt<X> {
                    type Value = Option<X>;
                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        write!(formatter, "An Option<{}64>", X::type_prefix())
                    }
                    fn visit_none<E>(self) -> Result<Self::Value, E>
                    where
                        E: de::Error {
                        Ok(None)
                    }
                    fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
                    where
                        D: Deserializer<'de>
                    {
                        Ok(Some(X::des_sat(d)?))
                    }
                }
                d.deserialize_option(VisitOptAmt::<A>(PhantomData))
            }
        }
    }
    pub mod as_btc {
        
        
        use serde::{Deserializer, Serializer};
        use util::amount::serde::SerdeAmount;
        pub fn serialize<A: SerdeAmount, S: Serializer>(a: &A, s: S) -> Result<S::Ok, S::Error> {
            a.ser_btc(s)
        }
        pub fn deserialize<'d, A: SerdeAmount, D: Deserializer<'d>>(d: D) -> Result<A, D::Error> {
            A::des_btc(d)
        }
        pub mod opt {
            
            
            use serde::{Deserializer, Serializer, de};
            use util::amount::serde::SerdeAmountForOpt;
            use std::fmt;
            use std::marker::PhantomData;
            pub fn serialize<A: SerdeAmountForOpt, S: Serializer>(
                a: &Option<A>,
                s: S,
            ) -> Result<S::Ok, S::Error> {
                match *a {
                    Some(a) => a.ser_btc_opt(s),
                    None => s.serialize_none(),
                }
            }
            pub fn deserialize<'d, A: SerdeAmountForOpt, D: Deserializer<'d>>(
                d: D,
            ) -> Result<Option<A>, D::Error> {
                struct VisitOptAmt<X>(PhantomData<X>);
                impl<'de, X :SerdeAmountForOpt> de::Visitor<'de> for VisitOptAmt<X> {
                    type Value = Option<X>;
                    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                        write!(formatter, "An Option<f64>")
                    }
                    fn visit_none<E>(self) -> Result<Self::Value, E>
                    where
                        E: de::Error {
                        Ok(None)
                    }
                    fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error>
                    where
                        D: Deserializer<'de>,
                    {
                        Ok(Some(X::des_btc(d)?))
                    }
                }
                d.deserialize_option(VisitOptAmt::<A>(PhantomData))
            }
        }
    }
}
#[cfg(test)]
mod tests {
    use super::*;
    use std::panic;
    use std::str::FromStr;
    #[cfg(feature = "serde")]
    use serde_test;
    #[test]
    fn add_sub_mul_div() {
        let sat = Amount::from_sat;
        let ssat = SignedAmount::from_sat;
        assert_eq!(sat(15) + sat(15), sat(30));
        assert_eq!(sat(15) - sat(15), sat(0));
        assert_eq!(sat(14) * 3, sat(42));
        assert_eq!(sat(14) / 2, sat(7));
        assert_eq!(sat(14) % 3, sat(2));
        assert_eq!(ssat(15) - ssat(20), ssat(-5));
        assert_eq!(ssat(-14) * 3, ssat(-42));
        assert_eq!(ssat(-14) / 2, ssat(-7));
        assert_eq!(ssat(-14) % 3, ssat(-2));
        let mut b = ssat(-5);
        b += ssat(13);
        assert_eq!(b, ssat(8));
        b -= ssat(3);
        assert_eq!(b, ssat(5));
        b *= 6;
        assert_eq!(b, ssat(30));
        b /= 3;
        assert_eq!(b, ssat(10));
        b %= 3;
        assert_eq!(b, ssat(1));
        
        let result = panic::catch_unwind(|| Amount::max_value() + Amount::from_sat(1));
        assert!(result.is_err());
        let result = panic::catch_unwind(|| Amount::from_sat(8446744073709551615) * 3);
        assert!(result.is_err());
    }
    #[test]
    fn checked_arithmetic() {
        let sat = Amount::from_sat;
        let ssat = SignedAmount::from_sat;
        assert_eq!(sat(42).checked_add(sat(1)), Some(sat(43)));
        assert_eq!(SignedAmount::max_value().checked_add(ssat(1)), None);
        assert_eq!(SignedAmount::min_value().checked_sub(ssat(1)), None);
        assert_eq!(Amount::max_value().checked_add(sat(1)), None);
        assert_eq!(Amount::min_value().checked_sub(sat(1)), None);
        assert_eq!(sat(5).checked_sub(sat(3)), Some(sat(2)));
        assert_eq!(sat(5).checked_sub(sat(6)), None);
        assert_eq!(ssat(5).checked_sub(ssat(6)), Some(ssat(-1)));
        assert_eq!(sat(5).checked_rem(2), Some(sat(1)));
        assert_eq!(sat(5).checked_div(2), Some(sat(2))); 
        assert_eq!(ssat(-6).checked_div(2), Some(ssat(-3)));
        assert_eq!(ssat(-5).positive_sub(ssat(3)), None);
        assert_eq!(ssat(5).positive_sub(ssat(-3)), None);
        assert_eq!(ssat(3).positive_sub(ssat(5)), None);
        assert_eq!(ssat(3).positive_sub(ssat(3)), Some(ssat(0)));
        assert_eq!(ssat(5).positive_sub(ssat(3)), Some(ssat(2)));
    }
    #[test]
    fn floating_point() {
        use super::Denomination as D;
        let f = Amount::from_float_in;
        let sf = SignedAmount::from_float_in;
        let sat = Amount::from_sat;
        let ssat = SignedAmount::from_sat;
        assert_eq!(f(11.22, D::Bitcoin), Ok(sat(1122000000)));
        assert_eq!(sf(-11.22, D::MilliBitcoin), Ok(ssat(-1122000)));
        assert_eq!(f(11.22, D::Bit), Ok(sat(1122)));
        assert_eq!(sf(-1000.0, D::MilliSatoshi), Ok(ssat(-1)));
        assert_eq!(f(0.0001234, D::Bitcoin), Ok(sat(12340)));
        assert_eq!(sf(-0.00012345, D::Bitcoin), Ok(ssat(-12345)));
        assert_eq!(f(-100.0, D::MilliSatoshi), Err(ParseAmountError::Negative));
        assert_eq!(f(11.22, D::Satoshi), Err(ParseAmountError::TooPrecise));
        assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
        assert_eq!(sf(-100.0, D::MilliSatoshi), Err(ParseAmountError::TooPrecise));
        assert_eq!(f(42.123456781, D::Bitcoin), Err(ParseAmountError::TooPrecise));
        assert_eq!(sf(-184467440738.0, D::Bitcoin), Err(ParseAmountError::TooBig));
        assert_eq!(f(18446744073709551617.0, D::Satoshi), Err(ParseAmountError::TooBig));
        assert_eq!(
            f(SignedAmount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi),
            Err(ParseAmountError::TooBig)
        );
        assert_eq!(
            f(Amount::max_value().to_float_in(D::Satoshi) + 1.0, D::Satoshi),
            Err(ParseAmountError::TooBig)
        );
        let btc = move |f| SignedAmount::from_btc(f).unwrap();
        assert_eq!(btc(2.5).to_float_in(D::Bitcoin), 2.5);
        assert_eq!(btc(-2.5).to_float_in(D::MilliBitcoin), -2500.0);
        assert_eq!(btc(2.5).to_float_in(D::Satoshi), 250000000.0);
        assert_eq!(btc(-2.5).to_float_in(D::MilliSatoshi), -250000000000.0);
        let btc = move |f| Amount::from_btc(f).unwrap();
        assert_eq!(&btc(0.0012).to_float_in(D::Bitcoin).to_string(), "0.0012")
    }
    #[test]
    fn parsing() {
        use super::ParseAmountError as E;
        let btc = Denomination::Bitcoin;
        let sat = Denomination::Satoshi;
        let p = Amount::from_str_in;
        let sp = SignedAmount::from_str_in;
        assert_eq!(p("x", btc), Err(E::InvalidCharacter('x')));
        assert_eq!(p("-", btc), Err(E::InvalidFormat));
        assert_eq!(sp("-", btc), Err(E::InvalidFormat));
        assert_eq!(p("-1.0x", btc), Err(E::InvalidCharacter('x')));
        assert_eq!(p("0.0 ", btc), Err(ParseAmountError::InvalidCharacter(' ')));
        assert_eq!(p("0.000.000", btc), Err(E::InvalidFormat));
        let more_than_max = format!("1{}", Amount::max_value());
        assert_eq!(p(&more_than_max, btc), Err(E::TooBig));
        assert_eq!(p("0.000000042", btc), Err(E::TooPrecise));
        assert_eq!(p("1", btc), Ok(Amount::from_sat(1_000_000_00)));
        assert_eq!(sp("-.5", btc), Ok(SignedAmount::from_sat(-500_000_00)));
        assert_eq!(p("1.1", btc), Ok(Amount::from_sat(1_100_000_00)));
        assert_eq!(p("100", sat), Ok(Amount::from_sat(100)));
        assert_eq!(p("55", sat), Ok(Amount::from_sat(55)));
        assert_eq!(p("5500000000000000000", sat), Ok(Amount::from_sat(5_500_000_000_000_000_000)));
        
        assert_eq!(p("5500000000000000000.", sat), Ok(Amount::from_sat(5_500_000_000_000_000_000)));
        assert_eq!(
            p("12345678901.12345678", btc),
            Ok(Amount::from_sat(12_345_678_901__123_456_78))
        );
        
        let amount = Amount::from_sat(i64::max_value() as u64);
        assert_eq!(Amount::from_str_in(&amount.to_string_in(sat), sat), Ok(amount));
        assert_eq!(Amount::from_str_in(&(amount+Amount(1)).to_string_in(sat), sat), Err(E::TooBig));
        assert_eq!(p("12.000", Denomination::MilliSatoshi), Err(E::TooPrecise));
        
        assert_eq!(p("100000000000000.0000000000000000000000000000000000", Denomination::Bitcoin), Err(E::TooBig));
        
        assert_eq!(p("100000000000000.00000000000000000000000000000000000", Denomination::Bitcoin), Err(E::InputTooLarge));
    }
    #[test]
    fn to_string() {
        use super::Denomination as D;
        assert_eq!(Amount::ONE_BTC.to_string_in(D::Bitcoin), "1.00000000");
        assert_eq!(Amount::ONE_BTC.to_string_in(D::Satoshi), "100000000");
        assert_eq!(Amount::ONE_SAT.to_string_in(D::Bitcoin), "0.00000001");
        assert_eq!(SignedAmount::from_sat(-42).to_string_in(D::Bitcoin), "-0.00000042");
        assert_eq!(Amount::ONE_BTC.to_string_with_denomination(D::Bitcoin), "1.00000000 BTC");
        assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::MilliSatoshi), "1000 msat");
        assert_eq!(
            SignedAmount::ONE_BTC.to_string_with_denomination(D::Satoshi),
            "100000000 satoshi"
        );
        assert_eq!(Amount::ONE_SAT.to_string_with_denomination(D::Bitcoin), "0.00000001 BTC");
        assert_eq!(
            SignedAmount::from_sat(-42).to_string_with_denomination(D::Bitcoin),
            "-0.00000042 BTC"
        );
    }
    #[test]
    fn test_unsigned_signed_conversion() {
        use super::ParseAmountError as E;
        let sa = SignedAmount::from_sat;
        let ua = Amount::from_sat;
        assert_eq!(Amount::max_value().to_signed(),  Err(E::TooBig));
        assert_eq!(ua(i64::max_value() as u64).to_signed(),  Ok(sa(i64::max_value())));
        assert_eq!(ua(0).to_signed(),  Ok(sa(0)));
        assert_eq!(ua(1).to_signed(), Ok( sa(1)));
        assert_eq!(ua(1).to_signed(),  Ok(sa(1)));
        assert_eq!(ua(i64::max_value() as u64 + 1).to_signed(),  Err(E::TooBig));
        assert_eq!(sa(-1).to_unsigned(), Err(E::Negative));
        assert_eq!(sa(i64::max_value()).to_unsigned(), Ok(ua(i64::max_value() as u64)));
        assert_eq!(sa(0).to_unsigned().unwrap().to_signed(), Ok(sa(0)));
        assert_eq!(sa(1).to_unsigned().unwrap().to_signed(), Ok(sa(1)));
        assert_eq!(sa(i64::max_value()).to_unsigned().unwrap().to_signed(), Ok(sa(i64::max_value())));
    }
    #[test]
    fn from_str() {
        use super::ParseAmountError as E;
        let p = Amount::from_str;
        let sp = SignedAmount::from_str;
        assert_eq!(p("x BTC"), Err(E::InvalidCharacter('x')));
        assert_eq!(p("5 BTC BTC"), Err(E::InvalidFormat));
        assert_eq!(p("5 5 BTC"), Err(E::InvalidFormat));
        assert_eq!(p("5 BCH"), Err(E::UnknownDenomination("BCH".to_owned())));
        assert_eq!(p("-1 BTC"), Err(E::Negative));
        assert_eq!(p("-0.0 BTC"), Err(E::Negative));
        assert_eq!(p("0.123456789 BTC"), Err(E::TooPrecise));
        assert_eq!(sp("-0.1 satoshi"), Err(E::TooPrecise));
        assert_eq!(p("0.123456 mBTC"), Err(E::TooPrecise));
        assert_eq!(sp("-1.001 bits"), Err(E::TooPrecise));
        assert_eq!(sp("-200000000000 BTC"), Err(E::TooBig));
        assert_eq!(p("18446744073709551616 sat"), Err(E::TooBig));
        assert_eq!(sp("0 msat"), Err(E::TooPrecise));
        assert_eq!(sp("-0 msat"), Err(E::TooPrecise));
        assert_eq!(sp("000 msat"), Err(E::TooPrecise));
        assert_eq!(sp("-000 msat"), Err(E::TooPrecise));
        assert_eq!(p("0 msat"), Err(E::TooPrecise));
        assert_eq!(p("-0 msat"), Err(E::TooPrecise));
        assert_eq!(p("000 msat"), Err(E::TooPrecise));
        assert_eq!(p("-000 msat"), Err(E::TooPrecise));
        assert_eq!(p(".5 bits"), Ok(Amount::from_sat(50)));
        assert_eq!(sp("-.5 bits"), Ok(SignedAmount::from_sat(-50)));
        assert_eq!(p("0.00253583 BTC"), Ok(Amount::from_sat(253583)));
        assert_eq!(sp("-5 satoshi"), Ok(SignedAmount::from_sat(-5)));
        assert_eq!(p("0.10000000 BTC"), Ok(Amount::from_sat(100_000_00)));
        assert_eq!(sp("-100 bits"), Ok(SignedAmount::from_sat(-10_000)));
    }
    #[test]
    fn to_from_string_in() {
        use super::Denomination as D;
        let ua_str = Amount::from_str_in;
        let ua_sat = Amount::from_sat;
        let sa_str = SignedAmount::from_str_in;
        let sa_sat = SignedAmount::from_sat;
        assert_eq!("0.50", Amount::from_sat(50).to_string_in(D::Bit));
        assert_eq!("-0.50", SignedAmount::from_sat(-50).to_string_in(D::Bit));
        assert_eq!("0.00253583", Amount::from_sat(253583).to_string_in(D::Bitcoin));
        assert_eq!("-5", SignedAmount::from_sat(-5).to_string_in(D::Satoshi));
        assert_eq!("0.10000000", Amount::from_sat(100_000_00).to_string_in(D::Bitcoin));
        assert_eq!("-100.00", SignedAmount::from_sat(-10_000).to_string_in(D::Bit));
        assert_eq!(ua_str(&ua_sat(0).to_string_in(D::Satoshi), D::Satoshi), Ok(ua_sat(0)));
        assert_eq!(ua_str(&ua_sat(500).to_string_in(D::Bitcoin), D::Bitcoin), Ok(ua_sat(500)));
        assert_eq!(ua_str(&ua_sat(21_000_000).to_string_in(D::Bit), D::Bit), Ok(ua_sat(21_000_000)));
        assert_eq!(ua_str(&ua_sat(1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(ua_sat(1)));
        assert_eq!(ua_str(&ua_sat(1_000_000_000_000).to_string_in(D::MilliBitcoin), D::MilliBitcoin), Ok(ua_sat(1_000_000_000_000)));
        assert_eq!(ua_str(&ua_sat(u64::max_value()).to_string_in(D::MilliBitcoin), D::MilliBitcoin),  Err(ParseAmountError::TooBig));
        assert_eq!(sa_str(&sa_sat(-1).to_string_in(D::MicroBitcoin), D::MicroBitcoin), Ok(sa_sat(-1)));
        assert_eq!(sa_str(&sa_sat(i64::max_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
        
        assert_eq!(sa_str(&sa_sat(i64::min_value()).to_string_in(D::Satoshi), D::MicroBitcoin), Err(ParseAmountError::TooBig));
    }
    #[test]
    fn to_string_with_denomination_from_str_roundtrip() {
        use super::Denomination as D;
        let amt = Amount::from_sat(42);
        let denom = Amount::to_string_with_denomination;
        assert_eq!(Amount::from_str(&denom(amt, D::Bitcoin)), Ok(amt));
        assert_eq!(Amount::from_str(&denom(amt, D::MilliBitcoin)), Ok(amt));
        assert_eq!(Amount::from_str(&denom(amt, D::MicroBitcoin)), Ok(amt));
        assert_eq!(Amount::from_str(&denom(amt, D::Bit)), Ok(amt));
        assert_eq!(Amount::from_str(&denom(amt, D::Satoshi)), Ok(amt));
        assert_eq!(Amount::from_str(&denom(amt, D::MilliSatoshi)), Ok(amt));
        assert_eq!(Amount::from_str("42 satoshi BTC"), Err(ParseAmountError::InvalidFormat));
        assert_eq!(SignedAmount::from_str("-42 satoshi BTC"), Err(ParseAmountError::InvalidFormat));
    }
    #[cfg(feature = "serde")]
    #[test]
    fn serde_as_sat() {
        #[derive(Serialize, Deserialize, PartialEq, Debug)]
        struct T {
            #[serde(with = "::util::amount::serde::as_sat")]
            pub amt: Amount,
            #[serde(with = "::util::amount::serde::as_sat")]
            pub samt: SignedAmount,
        }
        serde_test::assert_tokens(
            &T {
                amt: Amount::from_sat(123456789),
                samt: SignedAmount::from_sat(-123456789),
            },
            &[
                serde_test::Token::Struct {
                    name: "T",
                    len: 2,
                },
                serde_test::Token::Str("amt"),
                serde_test::Token::U64(123456789),
                serde_test::Token::Str("samt"),
                serde_test::Token::I64(-123456789),
                serde_test::Token::StructEnd,
            ],
        );
    }
    #[cfg(feature = "serde")]
    #[test]
    fn serde_as_btc() {
        use serde_json;
        #[derive(Serialize, Deserialize, PartialEq, Debug)]
        struct T {
            #[serde(with = "::util::amount::serde::as_btc")]
            pub amt: Amount,
            #[serde(with = "::util::amount::serde::as_btc")]
            pub samt: SignedAmount,
        }
        let orig = T {
            amt: Amount::from_sat(21_000_000__000_000_01),
            samt: SignedAmount::from_sat(-21_000_000__000_000_01),
        };
        let json = "{\"amt\": 21000000.00000001, \
                    \"samt\": -21000000.00000001}";
        let t: T = serde_json::from_str(&json).unwrap();
        assert_eq!(t, orig);
        let value: serde_json::Value = serde_json::from_str(&json).unwrap();
        assert_eq!(t, serde_json::from_value(value).unwrap());
        
        let t: Result<T, serde_json::Error> =
            serde_json::from_str("{\"amt\": 1000000.000000001, \"samt\": 1}");
        assert!(t.unwrap_err().to_string().contains(&ParseAmountError::TooPrecise.to_string()));
        let t: Result<T, serde_json::Error> = serde_json::from_str("{\"amt\": -1, \"samt\": 1}");
        assert!(t.unwrap_err().to_string().contains(&ParseAmountError::Negative.to_string()));
    }
    #[cfg(feature = "serde")]
    #[test]
    fn serde_as_btc_opt() {
        use serde_json;
        #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
        struct T {
            #[serde(default, with = "::util::amount::serde::as_btc::opt")]
            pub amt: Option<Amount>,
            #[serde(default, with = "::util::amount::serde::as_btc::opt")]
            pub samt: Option<SignedAmount>,
        }
        let with = T {
            amt: Some(Amount::from_sat(2__500_000_00)),
            samt: Some(SignedAmount::from_sat(-2__500_000_00)),
        };
        let without = T {
            amt: None,
            samt: None,
        };
        
        for s in [&with, &without].iter() {
            let v = serde_json::to_string(s).unwrap();
            let w : T = serde_json::from_str(&v).unwrap();
            assert_eq!(w, **s);
        }
        let t: T = serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
        assert_eq!(t, with);
        let t: T = serde_json::from_str("{}").unwrap();
        assert_eq!(t, without);
        let value_with: serde_json::Value =
            serde_json::from_str("{\"amt\": 2.5, \"samt\": -2.5}").unwrap();
        assert_eq!(with, serde_json::from_value(value_with).unwrap());
        let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
        assert_eq!(without, serde_json::from_value(value_without).unwrap());
    }
    #[cfg(feature = "serde")]
    #[test]
    fn serde_as_sat_opt() {
        use serde_json;
        #[derive(Serialize, Deserialize, PartialEq, Debug, Eq)]
        struct T {
            #[serde(default, with = "::util::amount::serde::as_sat::opt")]
            pub amt: Option<Amount>,
            #[serde(default, with = "::util::amount::serde::as_sat::opt")]
            pub samt: Option<SignedAmount>,
        }
        let with = T {
            amt: Some(Amount::from_sat(2__500_000_00)),
            samt: Some(SignedAmount::from_sat(-2__500_000_00)),
        };
        let without = T {
            amt: None,
            samt: None,
        };
        
        for s in [&with, &without].iter() {
            let v = serde_json::to_string(s).unwrap();
            let w : T = serde_json::from_str(&v).unwrap();
            assert_eq!(w, **s);
        }
        let t: T = serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
        assert_eq!(t, with);
        let t: T = serde_json::from_str("{}").unwrap();
        assert_eq!(t, without);
        let value_with: serde_json::Value =
            serde_json::from_str("{\"amt\": 250000000, \"samt\": -250000000}").unwrap();
        assert_eq!(with, serde_json::from_value(value_with).unwrap());
        let value_without: serde_json::Value = serde_json::from_str("{}").unwrap();
        assert_eq!(without, serde_json::from_value(value_without).unwrap());
    }
}