bitcoin_rpc_types/
types.rs

1//! Core schema types for Bitcoin RPC API definitions
2//!
3//! Fundamental, serde-friendly types to represent Bitcoin RPC method
4//! definitions, arguments, and results.
5
6use std::collections::BTreeMap;
7use std::path::Path;
8
9use serde::{Deserialize, Serialize};
10use thiserror::Error;
11
12/// Bitcoin method argument specification
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct BtcArgument {
15    /// Names of the argument
16    pub names: Vec<String>,
17    /// Description of the argument
18    pub description: String,
19    /// One-line description of the argument
20    #[serde(default, rename = "oneline_description")]
21    pub oneline_description: String,
22    /// Whether the argument can also be passed positionally
23    #[serde(default, rename = "also_positional")]
24    pub also_positional: bool,
25    /// Type string representation
26    #[serde(default, rename = "type_str")]
27    pub type_str: Option<Vec<String>>,
28    /// Whether the argument is required
29    pub required: bool,
30    /// Whether the argument is hidden from documentation
31    #[serde(default)]
32    pub hidden: bool,
33    /// Type of the argument
34    #[serde(rename = "type")]
35    pub type_: String,
36}
37
38/// Bitcoin method result specification
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct BtcResult {
41    /// Type of the result
42    #[serde(rename = "type")]
43    pub type_: String,
44    /// Whether the result is optional
45    #[serde(default, rename = "optional")]
46    pub optional: bool,
47    /// Whether the result is required (computed from optional)
48    #[serde(skip)]
49    pub required: bool,
50    /// Description of the result
51    pub description: String,
52    /// Whether to skip type checking for this result
53    #[serde(default, rename = "skip_type_check")]
54    pub skip_type_check: bool,
55    /// Key name for the result
56    #[serde(default, rename = "key_name")]
57    pub key_name: String,
58    /// Condition for when this result is present
59    #[serde(default)]
60    pub condition: String,
61    /// Inner results for nested structures
62    #[serde(default)]
63    pub inner: Vec<BtcResult>,
64}
65
66impl Default for BtcResult {
67    /// Creates a default BtcResult with empty values
68    fn default() -> Self {
69        Self {
70            type_: String::new(),
71            optional: false,
72            required: true,
73            description: String::new(),
74            skip_type_check: false,
75            key_name: String::new(),
76            condition: String::new(),
77            inner: Vec::new(),
78        }
79    }
80}
81
82impl BtcResult {
83    /// Creates a new BtcResult with the specified parameters
84    pub fn new(
85        type_: String,
86        optional: bool,
87        description: String,
88        skip_type_check: bool,
89        key_name: String,
90        condition: String,
91        inner: Vec<BtcResult>,
92    ) -> Self {
93        Self {
94            type_,
95            optional,
96            required: !optional,
97            description,
98            skip_type_check,
99            key_name,
100            condition,
101            inner,
102        }
103    }
104
105    /// Post-processes the result to update required field based on optional
106    pub fn post_process(&mut self) {
107        self.required = !self.optional;
108        for inner in &mut self.inner {
109            inner.post_process();
110        }
111    }
112}
113
114/// Bitcoin method definition
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct BtcMethod {
117    /// Name of the method
118    pub name: String,
119    /// Description of the method
120    pub description: String,
121    /// Example usage of the method
122    #[serde(default)]
123    pub examples: String,
124    /// Names of the arguments
125    #[serde(default, rename = "argument_names")]
126    pub argument_names: Vec<String>,
127    /// Arguments for the method
128    pub arguments: Vec<BtcArgument>,
129    /// Results returned by the method
130    pub results: Vec<BtcResult>,
131}
132
133/// A collection of all Bitcoin RPC methods and their details
134#[derive(Debug, Default, Clone, Serialize, Deserialize)]
135pub struct ApiDefinition {
136    /// List of methods sorted by the method name
137    pub rpcs: BTreeMap<String, BtcMethod>,
138}
139
140impl ApiDefinition {
141    /// Creates a new empty API definition
142    pub fn new() -> Self { Self { rpcs: BTreeMap::new() } }
143
144    /// Loads an API definition from a JSON file
145    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
146        let content = std::fs::read_to_string(path)?;
147        let mut api_def: ApiDefinition = serde_json::from_str(&content)?;
148        for method in api_def.rpcs.values_mut() {
149            for result in &mut method.results {
150                result.post_process();
151            }
152        }
153        Ok(api_def)
154    }
155
156    /// Gets a method by name
157    pub fn get_method(&self, name: &str) -> Option<&BtcMethod> { self.rpcs.get(name) }
158}
159
160/// Error types for schema operations
161#[derive(Error, Debug)]
162pub enum SchemaError {
163    /// JSON parsing error
164    #[error("Failed to parse JSON: {0}")]
165    JsonParse(#[from] serde_json::Error),
166
167    /// IO error
168    #[error("IO error: {0}")]
169    Io(#[from] std::io::Error),
170}
171
172/// Result type for schema operations
173pub type Result<T> = std::result::Result<T, SchemaError>;