use core::cmp::Ordering;
use core::fmt::Debug;
use std::collections::{btree_map, BTreeSet};
use std::hash::Hash;
use amplify::confinement::{Confined, NonEmptyVec, SmallOrdMap, U16};
use bitcoin::Txid;
use strict_encoding::{DefaultBasedStrictDumb, StrictDecode, StrictDumb, StrictEncode};
use super::ExposedState;
use crate::commit_verify::Conceal;
use crate::operation::seal::GenesisSeal;
use crate::txout::BlindSeal;
use crate::{
AssignmentType, ExposedSeal, GraphSeal, RevealedData, RevealedState, RevealedValue, SecretSeal,
StateType, VoidState, LIB_NAME_RGB_COMMIT,
};
#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, From)]
#[wrapper(Deref)]
#[wrapper_mut(DerefMut)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB_COMMIT, dumb = Self(NonEmptyVec::with(A::strict_dumb())))]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(
crate = "serde_crate",
transparent,
bound = "A: serde::Serialize + serde::de::DeserializeOwned"
)
)]
pub struct AssignVec<A>(NonEmptyVec<A, U16>)
where A: StrictDumb + StrictEncode + StrictDecode;
impl<A: StrictDumb + StrictEncode + StrictDecode> AssignVec<A> {
pub fn with(vec: NonEmptyVec<A, U16>) -> Self { Self(vec) }
}
impl<A: StrictDumb + StrictEncode + StrictDecode> IntoIterator for AssignVec<A> {
type Item = A;
type IntoIter = std::vec::IntoIter<A>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Display, Error)]
#[display(doc_comments)]
pub struct UnknownDataError;
pub type AssignRights<Seal> = Assign<VoidState, Seal>;
pub type AssignFungible<Seal> = Assign<RevealedValue, Seal>;
pub type AssignData<Seal> = Assign<RevealedData, Seal>;
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(
lib = LIB_NAME_RGB_COMMIT,
tags = custom,
dumb = { Self::Revealed { seal: strict_dumb!(), state: strict_dumb!() } }
)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(crate = "serde_crate", rename_all = "camelCase", untagged)
)]
pub enum Assign<State: ExposedState, Seal: ExposedSeal> {
#[strict_type(tag = 0x00)]
Revealed { seal: Seal, state: State },
#[strict_type(tag = 0x01)]
ConfidentialSeal { seal: SecretSeal, state: State },
}
pub type RevealedAssign = Assign<RevealedState, BlindSeal<Txid>>;
impl<State: ExposedState, Seal: ExposedSeal> PartialOrd for Assign<State, Seal> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
}
impl<State: ExposedState, Seal: ExposedSeal> Ord for Assign<State, Seal> {
fn cmp(&self, other: &Self) -> Ordering {
self.to_confidential_seal()
.cmp(&other.to_confidential_seal())
}
}
impl<State: ExposedState, Seal: ExposedSeal> Assign<State, Seal> {
pub fn revealed(seal: Seal, state: State) -> Self { Assign::Revealed { seal, state } }
pub fn with_seal_replaced(assignment: &Self, seal: Seal) -> Self {
match assignment {
Assign::ConfidentialSeal { seal: _, state } | Assign::Revealed { seal: _, state } => {
Assign::Revealed {
seal,
state: state.clone(),
}
}
}
}
pub fn to_confidential_seal(&self) -> SecretSeal {
match self {
Assign::Revealed { seal, .. } => seal.conceal(),
Assign::ConfidentialSeal { seal, .. } => *seal,
}
}
pub fn revealed_seal(&self) -> Option<Seal> {
match self {
Assign::Revealed { seal, .. } => Some(*seal),
Assign::ConfidentialSeal { .. } => None,
}
}
pub fn as_revealed_state(&self) -> &State {
match self {
Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => state,
}
}
pub fn as_revealed_state_mut(&mut self) -> &mut State {
match self {
Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => state,
}
}
pub fn into_revealed_state(self) -> State {
match self {
Assign::Revealed { state, .. } | Assign::ConfidentialSeal { state, .. } => state,
}
}
pub fn as_revealed(&self) -> Option<(&Seal, &State)> {
match self {
Assign::Revealed { seal, state, .. } => Some((seal, state)),
_ => None,
}
}
pub fn to_revealed(&self) -> Option<(Seal, State)> {
match self {
Assign::Revealed { seal, state, .. } => Some((*seal, state.clone())),
_ => None,
}
}
pub fn into_revealed(self) -> Option<(Seal, State)> {
match self {
Assign::Revealed { seal, state, .. } => Some((seal, state)),
_ => None,
}
}
}
impl<State: ExposedState, Seal: ExposedSeal> Conceal for Assign<State, Seal>
where Self: Clone
{
type Concealed = Self;
fn conceal(&self) -> Self::Concealed {
match self {
Assign::Revealed { seal, state } => Self::ConfidentialSeal {
seal: seal.conceal(),
state: state.clone(),
},
Assign::ConfidentialSeal { .. } => self.clone(),
}
}
}
impl<State: ExposedState> Assign<State, GenesisSeal> {
pub fn transmutate_seals(&self) -> Assign<State, GraphSeal> {
match self {
Assign::ConfidentialSeal { seal, state } => Assign::ConfidentialSeal {
seal: *seal,
state: state.clone(),
},
Assign::Revealed { seal, state } => Assign::Revealed {
seal: seal.transmutate(),
state: state.clone(),
},
}
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
#[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB_COMMIT, tags = custom, dumb = Self::Declarative(strict_dumb!()))]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(
crate = "serde_crate",
rename_all = "camelCase",
tag = "type",
content = "items",
bound = "Seal: serde::Serialize + serde::de::DeserializeOwned"
)
)]
pub enum TypedAssigns<Seal: ExposedSeal> {
#[strict_type(tag = 0x00)]
Declarative(AssignVec<AssignRights<Seal>>),
#[strict_type(tag = 0x01)]
Fungible(AssignVec<AssignFungible<Seal>>),
#[strict_type(tag = 0x02)]
Structured(AssignVec<AssignData<Seal>>),
}
impl<Seal: ExposedSeal> Conceal for TypedAssigns<Seal> {
type Concealed = Self;
fn conceal(&self) -> Self::Concealed {
match self {
TypedAssigns::Declarative(s) => {
let concealed_iter = s.iter().map(AssignRights::<Seal>::conceal);
let inner = NonEmptyVec::try_from_iter(concealed_iter).expect("same size");
TypedAssigns::Declarative(AssignVec::with(inner))
}
TypedAssigns::Fungible(s) => {
let concealed_iter = s.iter().map(AssignFungible::<Seal>::conceal);
let inner = NonEmptyVec::try_from_iter(concealed_iter).expect("same size");
TypedAssigns::Fungible(AssignVec::with(inner))
}
TypedAssigns::Structured(s) => {
let concealed_iter = s.iter().map(AssignData::<Seal>::conceal);
let inner = NonEmptyVec::try_from_iter(concealed_iter).expect("same size");
TypedAssigns::Structured(AssignVec::with(inner))
}
}
}
}
impl<Seal: ExposedSeal> TypedAssigns<Seal> {
pub fn is_empty(&self) -> bool {
match self {
TypedAssigns::Declarative(set) => set.is_empty(),
TypedAssigns::Fungible(set) => set.is_empty(),
TypedAssigns::Structured(set) => set.is_empty(),
}
}
pub fn len_u16(&self) -> u16 {
match self {
TypedAssigns::Declarative(set) => set.len_u16(),
TypedAssigns::Fungible(set) => set.len_u16(),
TypedAssigns::Structured(set) => set.len_u16(),
}
}
#[inline]
pub fn state_type(&self) -> StateType {
match self {
TypedAssigns::Declarative(_) => StateType::Void,
TypedAssigns::Fungible(_) => StateType::Fungible,
TypedAssigns::Structured(_) => StateType::Structured,
}
}
#[inline]
pub fn is_declarative(&self) -> bool { matches!(self, TypedAssigns::Declarative(_)) }
#[inline]
pub fn is_fungible(&self) -> bool { matches!(self, TypedAssigns::Fungible(_)) }
#[inline]
pub fn is_structured(&self) -> bool { matches!(self, TypedAssigns::Structured(_)) }
#[inline]
pub fn as_declarative(&self) -> &[AssignRights<Seal>] {
match self {
TypedAssigns::Declarative(set) => set,
_ => Default::default(),
}
}
#[inline]
pub fn as_fungible(&self) -> &[AssignFungible<Seal>] {
match self {
TypedAssigns::Fungible(set) => set,
_ => Default::default(),
}
}
#[inline]
pub fn as_structured(&self) -> &[AssignData<Seal>] {
match self {
TypedAssigns::Structured(set) => set,
_ => Default::default(),
}
}
#[inline]
pub fn as_declarative_mut(&mut self) -> Option<&mut NonEmptyVec<AssignRights<Seal>, U16>> {
match self {
TypedAssigns::Declarative(set) => Some(set),
_ => None,
}
}
#[inline]
pub fn as_fungible_mut(&mut self) -> Option<&mut NonEmptyVec<AssignFungible<Seal>, U16>> {
match self {
TypedAssigns::Fungible(set) => Some(set),
_ => None,
}
}
#[inline]
pub fn as_structured_mut(&mut self) -> Option<&mut NonEmptyVec<AssignData<Seal>, U16>> {
match self {
TypedAssigns::Structured(set) => Some(set),
_ => None,
}
}
pub fn revealed_seal_at(&self, index: u16) -> Result<Option<Seal>, UnknownDataError> {
Ok(match self {
TypedAssigns::Declarative(vec) => vec
.get(index as usize)
.ok_or(UnknownDataError)?
.revealed_seal(),
TypedAssigns::Fungible(vec) => vec
.get(index as usize)
.ok_or(UnknownDataError)?
.revealed_seal(),
TypedAssigns::Structured(vec) => vec
.get(index as usize)
.ok_or(UnknownDataError)?
.revealed_seal(),
})
}
pub fn confidential_seal_at(&self, index: u16) -> Result<SecretSeal, UnknownDataError> {
Ok(match self {
TypedAssigns::Declarative(vec) => vec
.get(index as usize)
.ok_or(UnknownDataError)?
.to_confidential_seal(),
TypedAssigns::Fungible(vec) => vec
.get(index as usize)
.ok_or(UnknownDataError)?
.to_confidential_seal(),
TypedAssigns::Structured(vec) => vec
.get(index as usize)
.ok_or(UnknownDataError)?
.to_confidential_seal(),
})
}
pub fn reveal_seal(&mut self, seal: Seal) {
fn reveal<State: ExposedState, Seal: ExposedSeal>(
vec: &mut NonEmptyVec<Assign<State, Seal>, U16>,
revealed: Seal,
) {
for assign in vec.iter_mut() {
match assign {
Assign::ConfidentialSeal { seal, state } if *seal == revealed.conceal() => {
*assign = Assign::Revealed {
seal: revealed,
state: state.clone(),
}
}
_ => {}
}
}
}
match self {
TypedAssigns::Declarative(v) => reveal(v, seal),
TypedAssigns::Fungible(v) => reveal(v, seal),
TypedAssigns::Structured(v) => reveal(v, seal),
}
}
pub fn to_confidential_seals(&self) -> Vec<SecretSeal> {
match self {
TypedAssigns::Declarative(s) => s
.iter()
.map(AssignRights::<Seal>::to_confidential_seal)
.collect(),
TypedAssigns::Fungible(s) => s
.iter()
.map(AssignFungible::<Seal>::to_confidential_seal)
.collect(),
TypedAssigns::Structured(s) => s
.iter()
.map(AssignData::<Seal>::to_confidential_seal)
.collect(),
}
}
pub fn as_structured_state_at(&self, index: u16) -> Result<&RevealedData, UnknownDataError> {
match self {
TypedAssigns::Structured(vec) => Ok(vec
.get(index as usize)
.ok_or(UnknownDataError)?
.as_revealed_state()),
_ => Err(UnknownDataError),
}
}
pub fn as_fungible_state_at(&self, index: u16) -> Result<&RevealedValue, UnknownDataError> {
match self {
TypedAssigns::Fungible(vec) => Ok(vec
.get(index as usize)
.ok_or(UnknownDataError)?
.as_revealed_state()),
_ => Err(UnknownDataError),
}
}
pub fn into_structured_state_at(self, index: u16) -> Result<RevealedData, UnknownDataError> {
match self {
TypedAssigns::Structured(vec) => {
if index as usize >= vec.len() {
return Err(UnknownDataError);
}
Ok(vec.0.release().remove(index as usize).into_revealed_state())
}
_ => Err(UnknownDataError),
}
}
pub fn into_fungible_state_at(self, index: u16) -> Result<RevealedValue, UnknownDataError> {
match self {
TypedAssigns::Fungible(vec) => {
if index as usize >= vec.len() {
return Err(UnknownDataError);
}
Ok(vec.0.release().remove(index as usize).into_revealed_state())
}
_ => Err(UnknownDataError),
}
}
pub fn to_revealed_assign_at(
&self,
index: u16,
witness_id: Option<Txid>,
) -> Result<RevealedAssign, UnknownDataError> {
let (seal, state) = match self {
Self::Declarative(vec) => {
let (seal, _) = vec
.get(index as usize)
.and_then(Assign::as_revealed)
.ok_or(UnknownDataError)?;
(seal, RevealedState::Void)
}
Self::Fungible(vec) => {
let (seal, state) = vec
.get(index as usize)
.and_then(Assign::as_revealed)
.ok_or(UnknownDataError)?;
(seal, RevealedState::Fungible(*state))
}
Self::Structured(vec) => {
let (seal, state) = vec
.get(index as usize)
.and_then(Assign::as_revealed)
.ok_or(UnknownDataError)?;
(seal, RevealedState::Structured(state.clone()))
}
};
let seal = seal.with_witness_id(witness_id).ok_or(UnknownDataError)?;
Ok(Assign::revealed(seal, state))
}
}
impl TypedAssigns<GenesisSeal> {
pub fn transmutate_seals(&self) -> TypedAssigns<GraphSeal> {
match self {
TypedAssigns::Declarative(a) => TypedAssigns::Declarative(AssignVec::with(
Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals()))
.expect("same size"),
)),
TypedAssigns::Fungible(a) => TypedAssigns::Fungible(AssignVec::with(
Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals()))
.expect("same size"),
)),
TypedAssigns::Structured(a) => TypedAssigns::Structured(AssignVec::with(
Confined::try_from_iter(a.iter().map(|a| a.transmutate_seals()))
.expect("same size"),
)),
}
}
}
#[derive(Wrapper, WrapperMut, Clone, PartialEq, Eq, Debug, From)]
#[wrapper(Deref)]
#[wrapper_mut(DerefMut)]
#[derive(StrictType, StrictEncode, StrictDecode)]
#[strict_type(lib = LIB_NAME_RGB_COMMIT)]
#[cfg_attr(
feature = "serde",
derive(Serialize, Deserialize),
serde(
crate = "serde_crate",
transparent,
bound = "Seal: serde::Serialize + serde::de::DeserializeOwned"
)
)]
pub struct Assignments<Seal>(SmallOrdMap<AssignmentType, TypedAssigns<Seal>>)
where Seal: ExposedSeal;
impl<Seal: ExposedSeal> DefaultBasedStrictDumb for Assignments<Seal> {}
impl<Seal: ExposedSeal> Default for Assignments<Seal> {
fn default() -> Self { Self(empty!()) }
}
impl Assignments<GenesisSeal> {
pub fn transmutate_seals(&self) -> Assignments<GraphSeal> {
Assignments(
Confined::try_from_iter(self.iter().map(|(t, a)| (*t, a.transmutate_seals())))
.expect("same size"),
)
}
}
impl<Seal: ExposedSeal> IntoIterator for Assignments<Seal> {
type Item = (AssignmentType, TypedAssigns<Seal>);
type IntoIter = btree_map::IntoIter<AssignmentType, TypedAssigns<Seal>>;
fn into_iter(self) -> Self::IntoIter { self.0.into_iter() }
}
#[derive(Copy, Clone, Eq, PartialEq, Debug, From)]
pub enum AssignmentsRef<'op> {
#[from]
Genesis(&'op Assignments<GenesisSeal>),
#[from]
Graph(&'op Assignments<GraphSeal>),
}
impl AssignmentsRef<'_> {
pub fn len(&self) -> usize {
match self {
AssignmentsRef::Genesis(a) => a.len(),
AssignmentsRef::Graph(a) => a.len(),
}
}
pub fn is_empty(&self) -> bool { self.len() == 0 }
pub fn flat(&self) -> Assignments<GraphSeal> {
match *self {
AssignmentsRef::Genesis(a) => a.transmutate_seals(),
AssignmentsRef::Graph(a) => a.clone(),
}
}
pub fn types(&self) -> BTreeSet<AssignmentType> {
match self {
AssignmentsRef::Genesis(a) => a.keys().copied().collect(),
AssignmentsRef::Graph(a) => a.keys().copied().collect(),
}
}
pub fn has_type(&self, t: AssignmentType) -> bool {
match self {
AssignmentsRef::Genesis(a) => a.contains_key(&t),
AssignmentsRef::Graph(a) => a.contains_key(&t),
}
}
pub fn get(&self, t: AssignmentType) -> Option<TypedAssigns<GraphSeal>> {
match self {
AssignmentsRef::Genesis(a) => a.get(&t).map(TypedAssigns::transmutate_seals),
AssignmentsRef::Graph(a) => a.get(&t).cloned(),
}
}
}