pylon_functions/
registry.rs1use std::collections::HashMap;
4use std::sync::Mutex;
5
6use serde::{Deserialize, Serialize};
7
8use crate::protocol::FnType;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct FnDef {
17 pub name: String,
18 pub fn_type: FnType,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
21 pub args_schema: Option<serde_json::Value>,
22}
23
24pub struct FnRegistry {
34 fns: Mutex<HashMap<String, FnDef>>,
35}
36
37impl FnRegistry {
38 pub fn new() -> Self {
39 Self {
40 fns: Mutex::new(HashMap::new()),
41 }
42 }
43
44 pub fn register(&self, def: FnDef) {
46 self.fns.lock().unwrap().insert(def.name.clone(), def);
47 }
48
49 pub fn register_all(&self, defs: Vec<FnDef>) {
51 let mut fns = self.fns.lock().unwrap();
52 for def in defs {
53 fns.insert(def.name.clone(), def);
54 }
55 }
56
57 pub fn replace_all(&self, defs: Vec<FnDef>) {
62 let mut fns = self.fns.lock().unwrap();
63 fns.clear();
64 for def in defs {
65 fns.insert(def.name.clone(), def);
66 }
67 }
68
69 pub fn get(&self, name: &str) -> Option<FnDef> {
71 self.fns.lock().unwrap().get(name).cloned()
72 }
73
74 pub fn list(&self) -> Vec<FnDef> {
76 self.fns.lock().unwrap().values().cloned().collect()
77 }
78
79 pub fn list_by_type(&self, fn_type: FnType) -> Vec<FnDef> {
81 self.fns
82 .lock()
83 .unwrap()
84 .values()
85 .filter(|f| f.fn_type == fn_type)
86 .cloned()
87 .collect()
88 }
89
90 pub fn exists(&self, name: &str) -> bool {
92 self.fns.lock().unwrap().contains_key(name)
93 }
94
95 pub fn count(&self) -> usize {
97 self.fns.lock().unwrap().len()
98 }
99}
100
101impl Default for FnRegistry {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn register_and_lookup() {
113 let reg = FnRegistry::new();
114 reg.register(FnDef {
115 name: "placeBid".into(),
116 fn_type: FnType::Mutation,
117 args_schema: None,
118 });
119 reg.register(FnDef {
120 name: "getLots".into(),
121 fn_type: FnType::Query,
122 args_schema: None,
123 });
124
125 assert_eq!(reg.count(), 2);
126 assert!(reg.exists("placeBid"));
127 assert!(!reg.exists("nonexistent"));
128
129 let def = reg.get("placeBid").unwrap();
130 assert_eq!(def.fn_type, FnType::Mutation);
131 }
132
133 #[test]
134 fn list_by_type() {
135 let reg = FnRegistry::new();
136 reg.register_all(vec![
137 FnDef {
138 name: "a".into(),
139 fn_type: FnType::Mutation,
140 args_schema: None,
141 },
142 FnDef {
143 name: "b".into(),
144 fn_type: FnType::Query,
145 args_schema: None,
146 },
147 FnDef {
148 name: "c".into(),
149 fn_type: FnType::Mutation,
150 args_schema: None,
151 },
152 FnDef {
153 name: "d".into(),
154 fn_type: FnType::Action,
155 args_schema: None,
156 },
157 ]);
158
159 assert_eq!(reg.list_by_type(FnType::Mutation).len(), 2);
160 assert_eq!(reg.list_by_type(FnType::Query).len(), 1);
161 assert_eq!(reg.list_by_type(FnType::Action).len(), 1);
162 }
163}