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. This crate deliberately avoids
5//! generator/publishing logic and policy validation.
6
7use std::collections::BTreeMap;
8use std::path::Path;
9
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12
13/// Bitcoin method argument specification
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct BtcArgument {
16    pub names: Vec<String>,
17    pub description: String,
18    #[serde(default, rename = "oneline_description")]
19    pub oneline_description: String,
20    #[serde(default, rename = "also_positional")]
21    pub also_positional: bool,
22    #[serde(default, rename = "type_str")]
23    pub type_str: Option<Vec<String>>,
24    pub required: bool,
25    #[serde(default)]
26    pub hidden: bool,
27    #[serde(rename = "type")]
28    pub type_: String,
29}
30
31/// Bitcoin method result specification
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub struct BtcResult {
34    #[serde(rename = "type")]
35    pub type_: String,
36    #[serde(default, rename = "optional")]
37    pub optional: bool,
38    #[serde(skip)]
39    pub required: bool,
40    pub description: String,
41    #[serde(default, rename = "skip_type_check")]
42    pub skip_type_check: bool,
43    #[serde(default, rename = "key_name")]
44    pub key_name: String,
45    #[serde(default)]
46    pub condition: String,
47    #[serde(default)]
48    pub inner: Vec<BtcResult>,
49}
50
51impl Default for BtcResult {
52    fn default() -> Self {
53        Self {
54            type_: String::new(),
55            optional: false,
56            required: true,
57            description: String::new(),
58            skip_type_check: false,
59            key_name: String::new(),
60            condition: String::new(),
61            inner: Vec::new(),
62        }
63    }
64}
65
66impl BtcResult {
67    pub fn new(
68        type_: String,
69        optional: bool,
70        description: String,
71        skip_type_check: bool,
72        key_name: String,
73        condition: String,
74        inner: Vec<BtcResult>,
75    ) -> Self {
76        Self {
77            type_,
78            optional,
79            required: !optional,
80            description,
81            skip_type_check,
82            key_name,
83            condition,
84            inner,
85        }
86    }
87
88    pub fn post_process(&mut self) {
89        self.required = !self.optional;
90        for inner in &mut self.inner {
91            inner.post_process();
92        }
93    }
94}
95
96/// Bitcoin method definition
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct BtcMethod {
99    pub name: String,
100    pub description: String,
101    #[serde(default)]
102    pub examples: String,
103    #[serde(default, rename = "argument_names")]
104    pub argument_names: Vec<String>,
105    pub arguments: Vec<BtcArgument>,
106    pub results: Vec<BtcResult>,
107}
108
109/// Complete Bitcoin RPC API definition
110#[derive(Debug, Clone, Serialize, Deserialize)]
111pub struct ApiDefinition {
112    // List of methods sorted by the method name
113    pub rpcs: BTreeMap<String, BtcMethod>,
114}
115
116impl ApiDefinition {
117    pub fn new() -> Self { Self { rpcs: BTreeMap::new() } }
118
119    pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
120        let content = std::fs::read_to_string(path)?;
121        let mut api_def: ApiDefinition = serde_json::from_str(&content)?;
122        for method in api_def.rpcs.values_mut() {
123            for result in &mut method.results {
124                result.post_process();
125            }
126        }
127        Ok(api_def)
128    }
129
130    pub fn get_method(&self, name: &str) -> Option<&BtcMethod> { self.rpcs.get(name) }
131}
132
133impl Default for ApiDefinition {
134    fn default() -> Self {
135        Self::new()
136    }
137}
138
139/// Error types for schema operations
140#[derive(Error, Debug)]
141pub enum SchemaError {
142    #[error("Failed to parse JSON: {0}")]
143    JsonParse(#[from] serde_json::Error),
144
145    #[error("IO error: {0}")]
146    Io(#[from] std::io::Error),
147}
148
149/// Result type for schema operations
150pub type Result<T> = std::result::Result<T, SchemaError>;