Files
lightning/plugins/src/options.rs
2022-12-21 10:56:13 +01:00

190 lines
5.1 KiB
Rust

use serde::ser::{SerializeStruct, Serializer};
use serde::Serialize;
#[derive(Clone, Debug)]
pub enum Value {
String(String),
Integer(i64),
Boolean(bool),
OptString,
OptInteger,
OptBoolean,
}
impl Value {
/// Returns true if the `Value` is a String. Returns false otherwise.
///
/// For any Value on which `is_string` returns true, `as_str` is guaranteed
/// to return the string slice.
pub fn is_string(&self) -> bool {
self.as_str().is_some()
}
/// If the `Value` is a String, returns the associated str. Returns None
/// otherwise.
pub fn as_str(&self) -> Option<&str> {
match self {
Value::String(s) => Some(s),
_ => None,
}
}
/// Returns true if the `Value` is an integer between `i64::MIN` and
/// `i64::MAX`.
///
/// For any Value on which `is_i64` returns true, `as_i64` is guaranteed to
/// return the integer value.
pub fn is_i64(&self) -> bool {
self.as_i64().is_some()
}
/// If the `Value` is an integer, represent it as i64. Returns
/// None otherwise.
pub fn as_i64(&self) -> Option<i64> {
match *self {
Value::Integer(n) => Some(n),
_ => None,
}
}
/// Returns true if the `Value` is a Boolean. Returns false otherwise.
///
/// For any Value on which `is_boolean` returns true, `as_bool` is
/// guaranteed to return the boolean value.
pub fn is_boolean(&self) -> bool {
self.as_bool().is_some()
}
/// If the `Value` is a Boolean, returns the associated bool. Returns None
/// otherwise.
pub fn as_bool(&self) -> Option<bool> {
match *self {
Value::Boolean(b) => Some(b),
_ => None,
}
}
}
/// An stringly typed option that is passed to
#[derive(Clone, Debug)]
pub struct ConfigOption {
name: String,
pub(crate) value: Option<Value>,
default: Value,
description: String,
}
impl ConfigOption {
pub fn name(&self) -> &str {
&self.name
}
pub fn default(&self) -> &Value {
&self.default
}
}
// When we serialize we don't add the value. This is because we only
// ever serialize when we pass the option back to lightningd during
// the getmanifest call.
impl Serialize for ConfigOption {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut s = serializer.serialize_struct("ConfigOption", 4)?;
s.serialize_field("name", &self.name)?;
match &self.default {
Value::String(ss) => {
s.serialize_field("type", "string")?;
s.serialize_field("default", ss)?;
}
Value::Integer(i) => {
s.serialize_field("type", "int")?;
s.serialize_field("default", i)?;
}
Value::Boolean(b) => {
s.serialize_field("type", "bool")?;
s.serialize_field("default", b)?;
}
Value::OptString => {
s.serialize_field("type", "string")?;
}
Value::OptInteger => {
s.serialize_field("type", "int")?;
}
Value::OptBoolean => {
s.serialize_field("type", "bool")?;
}
}
s.serialize_field("description", &self.description)?;
s.end()
}
}
impl ConfigOption {
pub fn new(name: &str, default: Value, description: &str) -> Self {
Self {
name: name.to_string(),
default,
description: description.to_string(),
value: None,
}
}
pub fn value(&self) -> Value {
match &self.value {
None => self.default.clone(),
Some(v) => v.clone(),
}
}
pub fn description(&self) -> String {
self.description.clone()
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_option_serialize() {
let tests = vec![
(
ConfigOption::new("name", Value::String("default".to_string()), "description"),
json!({
"name": "name",
"description":"description",
"default": "default",
"type": "string",
}),
),
(
ConfigOption::new("name", Value::Integer(42), "description"),
json!({
"name": "name",
"description":"description",
"default": 42,
"type": "int",
}),
),
(
ConfigOption::new("name", Value::Boolean(true), "description"),
json!({
"name": "name",
"description":"description",
"default": true,
"type": "bool",
}),
),
];
for (input, expected) in tests.iter() {
let res = serde_json::to_value(input).unwrap();
assert_eq!(&res, expected);
}
}
}