use alloc::borrow::ToOwned;
use alloc::string::String;
use core::fmt::{self, Display, Formatter, Write};
use core::str::FromStr;
use amplify::num::apfloat::Round;
use amplify::num::{u1, u2, u3};
pub trait Flag: FromStr<Err = ParseFlagError> + Default {}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
#[cfg_attr(feature = "std", derive(Error))]
#[display(doc_comments)]
pub enum ParseFlagError {
UnknownFlag( &'static str, char),
UnknownFlags( &'static str, String),
MutuallyExclusiveFlags(
&'static str,
char,
char,
),
RequiredFlagAbsent( &'static str),
DuplicatedFlags( &'static str, String),
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum SignFlag {
#[display("u")]
Unsigned = 0,
#[display("s")]
Signed = 1,
}
impl Flag for SignFlag {}
impl Default for SignFlag {
#[inline]
fn default() -> Self { Self::Unsigned }
}
impl FromStr for SignFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("integer sign"));
}
let filtered = s.replace(&['u', 's'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("integer sign", filtered));
}
match (s.contains('u'), s.contains('s')) {
(true, false) => Ok(SignFlag::Unsigned),
(false, true) => Ok(SignFlag::Signed),
(true, true) => Err(ParseFlagError::MutuallyExclusiveFlags("integer sign", 'u', 's')),
(false, false) => Err(ParseFlagError::RequiredFlagAbsent("integer sign")),
}
}
}
impl SignFlag {
pub fn from_u1(val: u1) -> SignFlag {
match val.into_u8() {
v if v == SignFlag::Unsigned as u8 => SignFlag::Unsigned,
v if v == SignFlag::Signed as u8 => SignFlag::Signed,
_ => unreachable!(),
}
}
pub fn as_u1(self) -> u1 { u1::with(self as u8) }
}
impl From<u1> for SignFlag {
fn from(val: u1) -> SignFlag { SignFlag::from_u1(val) }
}
impl From<&SignFlag> for u1 {
fn from(flag: &SignFlag) -> u1 { flag.as_u1() }
}
impl From<SignFlag> for u1 {
fn from(flag: SignFlag) -> u1 { flag.as_u1() }
}
impl From<SignFlag> for bool {
fn from(flag: SignFlag) -> Self { flag == SignFlag::Signed }
}
impl From<&SignFlag> for bool {
fn from(flag: &SignFlag) -> Self { *flag == SignFlag::Signed }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum NoneEqFlag {
#[display("e")]
Equal = 1,
#[display("n")]
NonEqual = 0,
}
impl Flag for NoneEqFlag {}
impl Default for NoneEqFlag {
#[inline]
fn default() -> Self { Self::Equal }
}
impl FromStr for NoneEqFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("none-equality"));
}
let filtered = s.replace(&['e', 'n'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("none-equality", filtered));
}
match (s.contains('e'), s.contains('n')) {
(true, false) => Ok(NoneEqFlag::Equal),
(false, true) => Ok(NoneEqFlag::NonEqual),
(true, true) => Err(ParseFlagError::MutuallyExclusiveFlags("none-equality", 'e', 'n')),
(false, false) => Err(ParseFlagError::RequiredFlagAbsent("none-equality")),
}
}
}
impl NoneEqFlag {
pub fn from_u1(val: u1) -> NoneEqFlag {
match val.into_u8() {
v if v == NoneEqFlag::Equal as u8 => NoneEqFlag::Equal,
v if v == NoneEqFlag::NonEqual as u8 => NoneEqFlag::NonEqual,
_ => unreachable!(),
}
}
pub fn as_u1(self) -> u1 { u1::with(self as u8) }
}
impl From<u1> for NoneEqFlag {
fn from(val: u1) -> NoneEqFlag { NoneEqFlag::from_u1(val) }
}
impl From<&NoneEqFlag> for u1 {
fn from(flag: &NoneEqFlag) -> u1 { flag.as_u1() }
}
impl From<NoneEqFlag> for u1 {
fn from(flag: NoneEqFlag) -> u1 { flag.as_u1() }
}
impl From<NoneEqFlag> for bool {
fn from(flag: NoneEqFlag) -> Self { flag == NoneEqFlag::Equal }
}
impl From<&NoneEqFlag> for bool {
fn from(flag: &NoneEqFlag) -> Self { *flag == NoneEqFlag::Equal }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum FloatEqFlag {
#[display("e")]
Exact = 0,
#[display("r")]
Rounding = 1,
}
impl Flag for FloatEqFlag {}
impl Default for FloatEqFlag {
#[inline]
fn default() -> Self { Self::Exact }
}
impl FromStr for FloatEqFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("float equality"));
}
let filtered = s.replace(&['e', 'r'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("float equality", filtered));
}
match (s.contains('e'), s.contains('r')) {
(true, false) => Ok(FloatEqFlag::Exact),
(false, true) => Ok(FloatEqFlag::Rounding),
(true, true) => Err(ParseFlagError::MutuallyExclusiveFlags("float equality", 'e', 'r')),
(false, false) => Err(ParseFlagError::RequiredFlagAbsent("float equality")),
}
}
}
impl FloatEqFlag {
pub fn from_u1(val: u1) -> FloatEqFlag {
match val.into_u8() {
v if v == FloatEqFlag::Exact as u8 => FloatEqFlag::Exact,
v if v == FloatEqFlag::Rounding as u8 => FloatEqFlag::Rounding,
_ => unreachable!(),
}
}
pub fn as_u1(self) -> u1 { u1::with(self as u8) }
}
impl From<u1> for FloatEqFlag {
fn from(val: u1) -> FloatEqFlag { FloatEqFlag::from_u1(val) }
}
impl From<&FloatEqFlag> for u1 {
fn from(flag: &FloatEqFlag) -> u1 { flag.as_u1() }
}
impl From<FloatEqFlag> for u1 {
fn from(flag: FloatEqFlag) -> u1 { flag.as_u1() }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum RoundingFlag {
#[display("z")]
TowardsZero = 0,
#[display("n")]
TowardsNearest = 1,
#[display("f")]
Floor = 2,
#[display("c")]
Ceil = 3,
}
impl Flag for RoundingFlag {}
impl Default for RoundingFlag {
#[inline]
fn default() -> Self { Self::TowardsNearest }
}
impl FromStr for RoundingFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("float rounding"));
}
let filtered = s.replace(&['n', 'z', 'c', 'f'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("float rounding", filtered));
}
if s.len() > 1 {
return Err(ParseFlagError::MutuallyExclusiveFlags(
"float rounding",
s.as_bytes()[0].into(),
s.as_bytes()[1].into(),
));
}
if s.contains('n') {
Ok(RoundingFlag::TowardsNearest)
} else if s.contains('z') {
Ok(RoundingFlag::TowardsZero)
} else if s.contains('c') {
Ok(RoundingFlag::Ceil)
} else if s.contains('f') {
Ok(RoundingFlag::Floor)
} else {
Err(ParseFlagError::UnknownFlag("float rounding", s.as_bytes()[0].into()))
}
}
}
impl RoundingFlag {
pub fn from_u2(val: u2) -> Self {
match val.to_u8() {
v if v == RoundingFlag::TowardsZero as u8 => RoundingFlag::TowardsZero,
v if v == RoundingFlag::TowardsNearest as u8 => RoundingFlag::TowardsNearest,
v if v == RoundingFlag::Ceil as u8 => RoundingFlag::Ceil,
v if v == RoundingFlag::Floor as u8 => RoundingFlag::Floor,
_ => unreachable!(),
}
}
pub fn as_u2(self) -> u2 { u2::with(self as u8) }
}
impl From<u2> for RoundingFlag {
fn from(val: u2) -> RoundingFlag { RoundingFlag::from_u2(val) }
}
impl From<&RoundingFlag> for u2 {
fn from(flag: &RoundingFlag) -> u2 { flag.as_u2() }
}
impl From<RoundingFlag> for u2 {
fn from(flag: RoundingFlag) -> u2 { flag.as_u2() }
}
impl From<RoundingFlag> for Round {
fn from(flag: RoundingFlag) -> Self {
match flag {
RoundingFlag::TowardsZero => Round::TowardZero,
RoundingFlag::TowardsNearest => Round::NearestTiesToEven,
RoundingFlag::Floor => Round::TowardNegative,
RoundingFlag::Ceil => Round::TowardPositive,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct IntFlags {
pub signed: bool,
pub wrap: bool,
}
impl Flag for IntFlags {}
impl Display for IntFlags {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if self.signed {
f.write_char('s')?;
} else {
f.write_char('u')?;
}
if self.wrap {
f.write_char('w')
} else {
f.write_char('c')
}
}
}
impl FromStr for IntFlags {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let signed = match (s.contains('s'), s.contains('u')) {
(true, false) => true,
(false, true) => false,
(true, true) => {
return Err(ParseFlagError::MutuallyExclusiveFlags(
"integer serialization",
's',
'u',
))
}
(false, false) => {
return Err(ParseFlagError::RequiredFlagAbsent("integer serialization"))
}
};
let wrap = match (s.contains('w'), s.contains('c')) {
(true, false) => true,
(false, true) => false,
(true, true) => {
return Err(ParseFlagError::MutuallyExclusiveFlags("overflow", 'w', 'c'))
}
(false, false) => return Err(ParseFlagError::RequiredFlagAbsent("overflow")),
};
if s.len() > 2 {
return Err(ParseFlagError::UnknownFlags(
"integer serialization",
s.replace(&['s', 'u', 'c', 'w'][..], ""),
));
}
Ok(IntFlags { signed, wrap })
}
}
impl IntFlags {
pub fn from_u2(val: u2) -> Self {
let val = val.to_u8();
IntFlags { signed: val & 0x01 == 1, wrap: val & 0x02 >> 1 == 1 }
}
pub fn as_u2(self) -> u2 { u2::with(self.signed as u8 | ((self.wrap as u8) << 1)) }
#[inline]
pub fn unsigned_checked() -> Self { IntFlags { signed: false, wrap: false } }
#[inline]
pub fn signed_checked() -> Self { IntFlags { signed: true, wrap: false } }
#[inline]
pub fn unsigned_wrapped() -> Self { IntFlags { signed: false, wrap: true } }
#[inline]
pub fn signed_wrapped() -> Self { IntFlags { signed: true, wrap: true } }
}
impl From<u2> for IntFlags {
fn from(val: u2) -> IntFlags { IntFlags::from_u2(val) }
}
impl From<&IntFlags> for u2 {
fn from(flag: &IntFlags) -> u2 { flag.as_u2() }
}
impl From<IntFlags> for u2 {
fn from(flag: IntFlags) -> u2 { flag.as_u2() }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum MergeFlag {
#[display("s")]
Set = 0,
#[display("a")]
Add = 1,
#[display("n")]
And = 2,
#[display("o")]
Or = 3,
}
impl Flag for MergeFlag {}
impl Default for MergeFlag {
#[inline]
fn default() -> Self { Self::Set }
}
impl FromStr for MergeFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("merge operation"));
}
let filtered = s.replace(&['s', 'a', 'n', 'o'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("merge operation", filtered));
}
if s.len() > 1 {
return Err(ParseFlagError::MutuallyExclusiveFlags(
"merge",
s.as_bytes()[0].into(),
s.as_bytes()[1].into(),
));
}
if s.contains('s') {
Ok(MergeFlag::Set)
} else if s.contains('a') {
Ok(MergeFlag::Add)
} else if s.contains('n') {
Ok(MergeFlag::And)
} else if s.contains('o') {
Ok(MergeFlag::Or)
} else {
Err(ParseFlagError::UnknownFlag("merge operation", s.as_bytes()[0].into()))
}
}
}
impl MergeFlag {
pub fn from_u2(val: u2) -> Self {
match val.to_u8() {
v if v == MergeFlag::Set as u8 => MergeFlag::Set,
v if v == MergeFlag::Add as u8 => MergeFlag::Add,
v if v == MergeFlag::And as u8 => MergeFlag::And,
v if v == MergeFlag::Or as u8 => MergeFlag::Or,
_ => unreachable!(),
}
}
pub fn as_u2(self) -> u2 { u2::with(self as u8) }
}
impl From<u2> for MergeFlag {
fn from(val: u2) -> MergeFlag { MergeFlag::from_u2(val) }
}
impl From<&MergeFlag> for u2 {
fn from(flag: &MergeFlag) -> u2 { flag.as_u2() }
}
impl From<MergeFlag> for u2 {
fn from(flag: MergeFlag) -> u2 { flag.as_u2() }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum ExtendFlag {
#[display("e")]
Extend = 0,
#[display("f")]
Fail = 1,
}
impl Flag for ExtendFlag {}
impl Default for ExtendFlag {
#[inline]
fn default() -> Self { Self::Extend }
}
impl FromStr for ExtendFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("extension flag"));
}
let filtered = s.replace(&['e', 'f'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("extension flag", filtered));
}
match (s.contains('e'), s.contains('f')) {
(true, false) => Ok(ExtendFlag::Extend),
(false, true) => Ok(ExtendFlag::Fail),
(true, true) => Err(ParseFlagError::MutuallyExclusiveFlags("extension flag", 'e', 'f')),
(false, false) => Err(ParseFlagError::RequiredFlagAbsent("extension flag")),
}
}
}
impl ExtendFlag {
pub fn from_u1(val: u1) -> ExtendFlag {
match val.into_u8() {
v if v == ExtendFlag::Extend as u8 => ExtendFlag::Extend,
v if v == ExtendFlag::Fail as u8 => ExtendFlag::Fail,
_ => unreachable!(),
}
}
pub fn as_u1(self) -> u1 { u1::with(self as u8) }
}
impl From<u1> for ExtendFlag {
fn from(val: u1) -> ExtendFlag { ExtendFlag::from_u1(val) }
}
impl From<&ExtendFlag> for u1 {
fn from(flag: &ExtendFlag) -> u1 { flag.as_u1() }
}
impl From<ExtendFlag> for u1 {
fn from(flag: ExtendFlag) -> u1 { flag.as_u1() }
}
impl From<ExtendFlag> for bool {
fn from(flag: ExtendFlag) -> Self { flag == ExtendFlag::Fail }
}
impl From<&ExtendFlag> for bool {
fn from(flag: &ExtendFlag) -> Self { *flag == ExtendFlag::Fail }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum SplitFlag {
#[display("n")]
NoneNone = 0,
#[display("nn")]
NoneNoneOnEmpty = 1,
#[display("nz")]
NoneZeroOnEmpty = 2,
#[display("ee")]
ZeroZeroOnEmpty = 3,
#[display("cn")]
CutNone = 4,
#[display("cz")]
CutZero = 5,
#[display("zn")]
ZeroNone = 6,
#[display("zz")]
ZeroZero = 7,
}
impl Flag for SplitFlag {}
impl Default for SplitFlag {
#[inline]
fn default() -> Self { Self::NoneNone }
}
impl FromStr for SplitFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("split operation"));
}
Ok(match s {
"n" => SplitFlag::NoneNone,
"nn" => SplitFlag::NoneNoneOnEmpty,
"nz" => SplitFlag::NoneZeroOnEmpty,
"ee" => SplitFlag::ZeroZeroOnEmpty,
"cn" => SplitFlag::CutNone,
"cz" => SplitFlag::CutZero,
"zn" => SplitFlag::ZeroNone,
"zz" => SplitFlag::ZeroZero,
_ => return Err(ParseFlagError::UnknownFlags("split operation", s.to_owned())),
})
}
}
impl SplitFlag {
pub fn from_u3(val: u3) -> Self {
match val.to_u8() {
v if v == SplitFlag::NoneNone as u8 => SplitFlag::NoneNone,
v if v == SplitFlag::NoneNoneOnEmpty as u8 => SplitFlag::NoneNoneOnEmpty,
v if v == SplitFlag::NoneZeroOnEmpty as u8 => SplitFlag::NoneZeroOnEmpty,
v if v == SplitFlag::ZeroZeroOnEmpty as u8 => SplitFlag::ZeroZeroOnEmpty,
v if v == SplitFlag::CutNone as u8 => SplitFlag::CutNone,
v if v == SplitFlag::CutZero as u8 => SplitFlag::CutZero,
v if v == SplitFlag::ZeroNone as u8 => SplitFlag::ZeroNone,
v if v == SplitFlag::ZeroZero as u8 => SplitFlag::ZeroZero,
_ => unreachable!(),
}
}
pub fn as_u3(self) -> u3 { u3::with(self as u8) }
}
impl From<u3> for SplitFlag {
fn from(val: u3) -> Self { Self::from_u3(val) }
}
impl From<&SplitFlag> for u3 {
fn from(flag: &SplitFlag) -> u3 { flag.as_u3() }
}
impl From<SplitFlag> for u3 {
fn from(flag: SplitFlag) -> u3 { flag.as_u3() }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum InsertFlag {
#[display("l")]
FailOnLen = 0,
#[display("o")]
FailOnOffset = 1,
#[display("f")]
FailOnOffsetLen = 2,
#[display("e")]
Extend = 3,
#[display("a")]
Append = 4,
#[display("x")]
ExtendCut = 5,
#[display("c")]
Cut = 6,
#[display("s")]
Shorten = 7,
}
impl Flag for InsertFlag {}
impl Default for InsertFlag {
#[inline]
fn default() -> Self { Self::FailOnLen }
}
impl FromStr for InsertFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("insert operation"));
}
let filtered = s.replace(&['l', 'o', 'f', 'e', 'a', 'x', 'c', 's'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("insert operation", filtered));
}
if filtered.len() > 1 {
return Err(ParseFlagError::DuplicatedFlags("insert operation", filtered));
}
Ok(match filtered.as_bytes()[0].into() {
'l' => InsertFlag::FailOnLen,
'o' => InsertFlag::FailOnOffset,
'f' => InsertFlag::FailOnOffsetLen,
'e' => InsertFlag::Extend,
'a' => InsertFlag::Append,
'x' => InsertFlag::ExtendCut,
'c' => InsertFlag::Cut,
's' => InsertFlag::Shorten,
_ => unreachable!(),
})
}
}
impl InsertFlag {
pub fn from_u3(val: u3) -> Self {
match val.to_u8() {
v if v == InsertFlag::FailOnLen as u8 => InsertFlag::FailOnLen,
v if v == InsertFlag::FailOnOffset as u8 => InsertFlag::FailOnOffset,
v if v == InsertFlag::FailOnOffsetLen as u8 => InsertFlag::FailOnOffsetLen,
v if v == InsertFlag::Extend as u8 => InsertFlag::Extend,
v if v == InsertFlag::Append as u8 => InsertFlag::Append,
v if v == InsertFlag::ExtendCut as u8 => InsertFlag::ExtendCut,
v if v == InsertFlag::Cut as u8 => InsertFlag::Cut,
v if v == InsertFlag::Shorten as u8 => InsertFlag::Shorten,
_ => unreachable!(),
}
}
pub fn as_u3(self) -> u3 { u3::with(self as u8) }
}
impl From<u3> for InsertFlag {
fn from(val: u3) -> Self { Self::from_u3(val) }
}
impl From<&InsertFlag> for u3 {
fn from(flag: &InsertFlag) -> u3 { flag.as_u3() }
}
impl From<InsertFlag> for u3 {
fn from(flag: InsertFlag) -> u3 { flag.as_u3() }
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Display)]
pub enum DeleteFlag {
#[display("n")]
None = 0,
#[display("z")]
Zero = 1,
#[display("c")]
Cut = 2,
#[display("e")]
Extend = 3,
}
impl Flag for DeleteFlag {}
impl Default for DeleteFlag {
#[inline]
fn default() -> Self { Self::None }
}
impl FromStr for DeleteFlag {
type Err = ParseFlagError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Err(ParseFlagError::RequiredFlagAbsent("delete operation"));
}
let filtered = s.replace(&['n', 'z', 'c', 'e'][..], "");
if !filtered.is_empty() {
return Err(ParseFlagError::UnknownFlags("delete operation", filtered));
}
if filtered.len() > 1 {
return Err(ParseFlagError::DuplicatedFlags("delete operation", filtered));
}
Ok(match filtered.as_bytes()[0].into() {
'n' => DeleteFlag::None,
'z' => DeleteFlag::Zero,
'c' => DeleteFlag::Cut,
'e' => DeleteFlag::Extend,
_ => unreachable!(),
})
}
}
impl DeleteFlag {
pub fn from_u2(val: u2) -> Self {
match val.to_u8() {
v if v == DeleteFlag::None as u8 => DeleteFlag::None,
v if v == DeleteFlag::Zero as u8 => DeleteFlag::Zero,
v if v == DeleteFlag::Cut as u8 => DeleteFlag::Cut,
v if v == DeleteFlag::Extend as u8 => DeleteFlag::Extend,
_ => unreachable!(),
}
}
pub fn as_u2(self) -> u2 { u2::with(self as u8) }
}
impl From<u2> for DeleteFlag {
fn from(val: u2) -> Self { Self::from_u2(val) }
}
impl From<&DeleteFlag> for u2 {
fn from(flag: &DeleteFlag) -> u2 { flag.as_u2() }
}
impl From<DeleteFlag> for u2 {
fn from(flag: DeleteFlag) -> u2 { flag.as_u2() }
}