Skip to content

Commit

Permalink
cln-rpc: Add type for AmountOrAll and AmountOrAny
Browse files Browse the repository at this point in the history
  • Loading branch information
cdecker committed Feb 11, 2022
1 parent b320337 commit 6d256fd
Showing 1 changed file with 102 additions and 0 deletions.
102 changes: 102 additions & 0 deletions cln-rpc/src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,23 @@ pub enum ChannelStateChangeCause {
ONCHAIN,
}

/// An `Amount` that can also be `any`. Useful for cases in which you
/// want to delegate the Amount selection so someone else, e.g., an
/// amountless invoice.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum AmountOrAny {
Amount(Amount),
Any,
}

/// An amount that can also be `all`. Useful for cases where you want
/// to delegate the amount computation to the cln node.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum AmountOrAll {
Amount(Amount),
All,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Amount {
msat: u64,
Expand Down Expand Up @@ -75,6 +92,62 @@ impl Serialize for Amount {
}
}

impl Serialize for AmountOrAll {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
AmountOrAll::Amount(a) => serializer.serialize_str(&format!("{}msat", a.msat)),
AmountOrAll::All => serializer.serialize_str("all"),
}
}
}

impl Serialize for AmountOrAny {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
AmountOrAny::Amount(a) => serializer.serialize_str(&format!("{}msat", a.msat)),
AmountOrAny::Any => serializer.serialize_str("any"),
}
}
}

impl<'de> Deserialize<'de> for AmountOrAny {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
Ok(match s.to_lowercase().as_ref() {
"any" => AmountOrAny::Any,
v => AmountOrAny::Amount(
v.try_into()
.map_err(|_e| serde::de::Error::custom("could not parse amount"))?,
),
})
}
}

impl<'de> Deserialize<'de> for AmountOrAll {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s: String = Deserialize::deserialize(deserializer)?;
Ok(match s.to_lowercase().as_ref() {
"all" => AmountOrAll::All,
v => AmountOrAll::Amount(
v.try_into()
.map_err(|_e| serde::de::Error::custom("could not parse amount"))?,
),
})
}
}

impl TryFrom<&str> for Amount {
type Error = Error;
fn try_from(s: &str) -> Result<Amount> {
Expand Down Expand Up @@ -139,4 +212,33 @@ mod test {
assert_eq!(s, serialized);
}
}

#[test]
fn test_amount_all_any() {
let t = r#"{"any": "any", "all": "all", "not_any": "42msat", "not_all": "31337msat"}"#;

#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct T {
all: AmountOrAll,
not_all: AmountOrAll,
any: AmountOrAny,
not_any: AmountOrAny,
}

let parsed: T = serde_json::from_str(t).unwrap();

let expected = T {
all: AmountOrAll::All,
any: AmountOrAny::Any,
not_all: AmountOrAll::Amount(Amount { msat: 31337 }),
not_any: AmountOrAny::Amount(Amount { msat: 42 }),
};
assert_eq!(expected, parsed);

let serialized: String = serde_json::to_string(&parsed).unwrap();
assert_eq!(
serialized,
r#"{"all":"all","not_all":"31337msat","any":"any","not_any":"42msat"}"#
);
}
}

0 comments on commit 6d256fd

Please sign in to comment.