trident_client/
idl_loader.rs1use heck::ToSnakeCase;
2use std::fmt;
3use std::fs::File;
4use std::fs::{self};
5use std::io::Read;
6use std::path::PathBuf;
7
8use trident_idl_spec::Idl;
9
10#[derive(Debug)]
12pub enum IdlError {
13 IoError {
14 source: std::io::Error,
15 path: PathBuf,
16 operation: &'static str,
17 },
18 ParseError {
19 source: serde_json::Error,
20 path: PathBuf,
21 },
22 NoIdlsFound {
23 path: String,
24 },
25}
26
27impl fmt::Display for IdlError {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 IdlError::IoError {
31 source,
32 path,
33 operation,
34 } => {
35 write!(
36 f,
37 "Failed to {} '{}': {}",
38 operation,
39 path.display(),
40 source
41 )
42 }
43 IdlError::ParseError { source, path } => {
44 write!(
45 f,
46 "Failed to parse IDL file '{}': {}",
47 path.display(),
48 source
49 )
50 }
51 IdlError::NoIdlsFound { path } => {
52 write!(f, "No IDL files found in {}", path)
53 }
54 }
55 }
56}
57
58impl std::error::Error for IdlError {
59 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
60 match self {
61 IdlError::IoError { source, .. } => Some(source),
62 IdlError::ParseError { source, .. } => Some(source),
63 IdlError::NoIdlsFound { .. } => None,
64 }
65 }
66}
67
68pub fn load_idls(dir_path: PathBuf, program_name: Option<String>) -> Result<Vec<Idl>, IdlError> {
79 let mut idls = Vec::new();
80
81 let read_dir = fs::read_dir(&dir_path).map_err(|e| IdlError::IoError {
83 source: e,
84 path: dir_path.clone(),
85 operation: "read directory",
86 })?;
87
88 for entry_result in read_dir {
89 let entry = entry_result.map_err(|e| IdlError::IoError {
90 source: e,
91 path: dir_path.clone(),
92 operation: "read directory entry",
93 })?;
94
95 let path = entry.path();
96
97 if let Some(ref program_name) = program_name {
98 if path.is_file()
99 && !path
100 .file_name()
101 .and_then(|name| name.to_str())
102 .map(|name| name.trim_end_matches(".json") == program_name.to_snake_case())
104 .unwrap_or(false)
105 {
106 continue;
107 }
108 }
109
110 if path.is_file() && path.extension().and_then(|ext| ext.to_str()) == Some("json") {
112 let mut file = File::open(&path).map_err(|e| IdlError::IoError {
114 source: e,
115 path: path.clone(),
116 operation: "open file",
117 })?;
118
119 let mut json_content = String::new();
121 file.read_to_string(&mut json_content)
122 .map_err(|e| IdlError::IoError {
123 source: e,
124 path: path.clone(),
125 operation: "read file",
126 })?;
127
128 match serde_json::from_str::<Idl>(&json_content) {
130 Ok(parsed_idl) => {
131 idls.push(parsed_idl);
132 }
133 Err(e) => {
134 return Err(IdlError::ParseError {
136 source: e,
137 path: path.clone(),
138 });
139 }
140 }
141 }
142 }
143
144 if idls.is_empty() {
145 return Err(IdlError::NoIdlsFound {
146 path: dir_path.to_string_lossy().to_string(),
147 });
148 }
149
150 Ok(idls)
151}