yerba 0.2.0-arm-linux-gnu
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE.txt +21 -0
- data/README.md +528 -0
- data/exe/yerba +6 -0
- data/ext/yerba/extconf.rb +111 -0
- data/ext/yerba/yerba.c +752 -0
- data/lib/yerba/3.2/yerba.so +0 -0
- data/lib/yerba/3.3/yerba.so +0 -0
- data/lib/yerba/3.4/yerba.so +0 -0
- data/lib/yerba/4.0/yerba.so +0 -0
- data/lib/yerba/collection.rb +31 -0
- data/lib/yerba/document.rb +59 -0
- data/lib/yerba/formatting.rb +18 -0
- data/lib/yerba/location.rb +5 -0
- data/lib/yerba/map.rb +166 -0
- data/lib/yerba/scalar.rb +85 -0
- data/lib/yerba/sequence.rb +182 -0
- data/lib/yerba/version.rb +5 -0
- data/lib/yerba.rb +131 -0
- data/rust/Cargo.lock +805 -0
- data/rust/Cargo.toml +36 -0
- data/rust/build.rs +11 -0
- data/rust/cbindgen.toml +27 -0
- data/rust/rustfmt.toml +2 -0
- data/rust/src/commands/apply.rs +5 -0
- data/rust/src/commands/blank_lines.rs +58 -0
- data/rust/src/commands/check.rs +5 -0
- data/rust/src/commands/delete.rs +35 -0
- data/rust/src/commands/get.rs +194 -0
- data/rust/src/commands/init.rs +89 -0
- data/rust/src/commands/insert.rs +106 -0
- data/rust/src/commands/mate.rs +55 -0
- data/rust/src/commands/mod.rs +349 -0
- data/rust/src/commands/move_item.rs +54 -0
- data/rust/src/commands/move_key.rs +87 -0
- data/rust/src/commands/quote_style.rs +62 -0
- data/rust/src/commands/remove.rs +35 -0
- data/rust/src/commands/rename.rs +37 -0
- data/rust/src/commands/set.rs +59 -0
- data/rust/src/commands/sort.rs +52 -0
- data/rust/src/commands/sort_keys.rs +62 -0
- data/rust/src/commands/version.rs +8 -0
- data/rust/src/document.rs +2237 -0
- data/rust/src/error.rs +45 -0
- data/rust/src/ffi.rs +991 -0
- data/rust/src/json.rs +128 -0
- data/rust/src/lib.rs +29 -0
- data/rust/src/main.rs +72 -0
- data/rust/src/quote_style.rs +42 -0
- data/rust/src/selector.rs +241 -0
- data/rust/src/syntax.rs +262 -0
- data/rust/src/yaml_writer.rs +89 -0
- data/rust/src/yerbafile.rs +475 -0
- data/sig/yerba.rbs +3 -0
- data/yerba.gemspec +52 -0
- metadata +108 -0
data/rust/src/ffi.rs
ADDED
|
@@ -0,0 +1,991 @@
|
|
|
1
|
+
//! FFI bindings for the Yerba C API.
|
|
2
|
+
//!
|
|
3
|
+
//! # Safety
|
|
4
|
+
//!
|
|
5
|
+
//! All functions in this module require that pointer arguments are either valid or null
|
|
6
|
+
//! (where documented as nullable). The caller is responsible for freeing returned pointers
|
|
7
|
+
//! using the corresponding `_free` functions.
|
|
8
|
+
|
|
9
|
+
#![allow(clippy::missing_safety_doc)]
|
|
10
|
+
|
|
11
|
+
use std::ffi::{CStr, CString};
|
|
12
|
+
use std::os::raw::c_char;
|
|
13
|
+
use std::ptr;
|
|
14
|
+
|
|
15
|
+
use yaml_parser::SyntaxKind;
|
|
16
|
+
|
|
17
|
+
use crate::selector::Selector;
|
|
18
|
+
use crate::syntax::{detect_yaml_type, YerbaValueType};
|
|
19
|
+
use crate::{Document, InsertPosition, QuoteStyle};
|
|
20
|
+
|
|
21
|
+
#[repr(C)]
|
|
22
|
+
pub struct YerbaResult {
|
|
23
|
+
pub success: bool,
|
|
24
|
+
pub error: *mut c_char,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
impl YerbaResult {
|
|
28
|
+
fn ok() -> Self {
|
|
29
|
+
YerbaResult {
|
|
30
|
+
success: true,
|
|
31
|
+
error: ptr::null_mut(),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
fn err(message: &str) -> Self {
|
|
36
|
+
YerbaResult {
|
|
37
|
+
success: false,
|
|
38
|
+
error: CString::new(message).unwrap_or_default().into_raw(),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
#[repr(C)]
|
|
44
|
+
pub struct YerbaTypedValue {
|
|
45
|
+
pub text: *mut c_char,
|
|
46
|
+
pub value_type: YerbaValueType,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
#[repr(C)]
|
|
50
|
+
pub struct YerbaTypedList {
|
|
51
|
+
pub json: *mut c_char,
|
|
52
|
+
pub length: usize,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
#[repr(C)]
|
|
56
|
+
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
57
|
+
pub enum YerbaNodeType {
|
|
58
|
+
Scalar = 0,
|
|
59
|
+
Map = 1,
|
|
60
|
+
Sequence = 2,
|
|
61
|
+
NotFound = 3,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
#[repr(C)]
|
|
65
|
+
pub struct YerbaParseResult {
|
|
66
|
+
pub document: *mut Document,
|
|
67
|
+
pub error: *mut c_char,
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#[repr(C)]
|
|
71
|
+
pub struct YerbaLocation {
|
|
72
|
+
pub start_offset: usize,
|
|
73
|
+
pub end_offset: usize,
|
|
74
|
+
pub start_line: usize,
|
|
75
|
+
pub start_column: usize,
|
|
76
|
+
pub end_line: usize,
|
|
77
|
+
pub end_column: usize,
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
#[repr(C)]
|
|
81
|
+
pub struct YerbaGetResult {
|
|
82
|
+
pub is_list: bool,
|
|
83
|
+
pub node_type: YerbaNodeType,
|
|
84
|
+
pub single: YerbaTypedValue,
|
|
85
|
+
pub list: YerbaTypedList,
|
|
86
|
+
pub location: YerbaLocation,
|
|
87
|
+
pub key_name: *mut c_char,
|
|
88
|
+
pub key_location: YerbaLocation,
|
|
89
|
+
pub error: *mut c_char,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[no_mangle]
|
|
93
|
+
pub unsafe extern "C" fn yerba_document_parse_file(path: *const c_char) -> YerbaParseResult {
|
|
94
|
+
if path.is_null() {
|
|
95
|
+
return YerbaParseResult {
|
|
96
|
+
document: ptr::null_mut(),
|
|
97
|
+
error: CString::new("path is null").unwrap_or_default().into_raw(),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
let path_string = match CStr::from_ptr(path).to_str() {
|
|
102
|
+
Ok(string) => string,
|
|
103
|
+
Err(e) => {
|
|
104
|
+
return YerbaParseResult {
|
|
105
|
+
document: ptr::null_mut(),
|
|
106
|
+
error: CString::new(format!("Invalid UTF-8 in path: {}", e))
|
|
107
|
+
.unwrap_or_default()
|
|
108
|
+
.into_raw(),
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
match Document::parse_file(path_string) {
|
|
114
|
+
Ok(document) => YerbaParseResult {
|
|
115
|
+
document: Box::into_raw(Box::new(document)),
|
|
116
|
+
error: ptr::null_mut(),
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
Err(e) => YerbaParseResult {
|
|
120
|
+
document: ptr::null_mut(),
|
|
121
|
+
error: CString::new(e.to_string()).unwrap_or_default().into_raw(),
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
#[no_mangle]
|
|
127
|
+
pub unsafe extern "C" fn yerba_document_parse(content: *const c_char) -> YerbaParseResult {
|
|
128
|
+
if content.is_null() {
|
|
129
|
+
return YerbaParseResult {
|
|
130
|
+
document: ptr::null_mut(),
|
|
131
|
+
error: CString::new("content is null").unwrap_or_default().into_raw(),
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let content_string = match CStr::from_ptr(content).to_str() {
|
|
136
|
+
Ok(string) => string,
|
|
137
|
+
Err(e) => {
|
|
138
|
+
return YerbaParseResult {
|
|
139
|
+
document: ptr::null_mut(),
|
|
140
|
+
error: CString::new(format!("Invalid UTF-8: {}", e))
|
|
141
|
+
.unwrap_or_default()
|
|
142
|
+
.into_raw(),
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
match Document::parse(content_string) {
|
|
148
|
+
Ok(document) => YerbaParseResult {
|
|
149
|
+
document: Box::into_raw(Box::new(document)),
|
|
150
|
+
error: ptr::null_mut(),
|
|
151
|
+
},
|
|
152
|
+
|
|
153
|
+
Err(e) => YerbaParseResult {
|
|
154
|
+
document: ptr::null_mut(),
|
|
155
|
+
error: CString::new(e.to_string()).unwrap_or_default().into_raw(),
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
fn compute_location(source: &str, start_offset: usize, end_offset: usize) -> YerbaLocation {
|
|
161
|
+
let start = start_offset.min(source.len());
|
|
162
|
+
let end = end_offset.min(source.len());
|
|
163
|
+
|
|
164
|
+
let before_start = &source[..start];
|
|
165
|
+
let start_line = before_start.chars().filter(|c| *c == '\n').count() + 1;
|
|
166
|
+
let start_column = start - before_start.rfind('\n').map(|p| p + 1).unwrap_or(0);
|
|
167
|
+
|
|
168
|
+
let before_end = &source[..end];
|
|
169
|
+
let end_line = before_end.chars().filter(|c| *c == '\n').count() + 1;
|
|
170
|
+
let end_column = end - before_end.rfind('\n').map(|p| p + 1).unwrap_or(0);
|
|
171
|
+
|
|
172
|
+
YerbaLocation {
|
|
173
|
+
start_offset: start,
|
|
174
|
+
end_offset: end,
|
|
175
|
+
start_line,
|
|
176
|
+
start_column,
|
|
177
|
+
end_line,
|
|
178
|
+
end_column,
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const EMPTY_LOCATION: YerbaLocation = YerbaLocation {
|
|
183
|
+
start_offset: 0,
|
|
184
|
+
end_offset: 0,
|
|
185
|
+
start_line: 0,
|
|
186
|
+
start_column: 0,
|
|
187
|
+
end_line: 0,
|
|
188
|
+
end_column: 0,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
#[no_mangle]
|
|
192
|
+
pub unsafe extern "C" fn yerba_document_free(document: *mut Document) {
|
|
193
|
+
if !document.is_null() {
|
|
194
|
+
drop(Box::from_raw(document));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
#[no_mangle]
|
|
199
|
+
pub unsafe extern "C" fn yerba_document_get(document: *const Document, path: *const c_char) -> YerbaGetResult {
|
|
200
|
+
let document = &*document;
|
|
201
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
202
|
+
|
|
203
|
+
let selector = Selector::parse(path_string);
|
|
204
|
+
|
|
205
|
+
if let Err(e) = Document::validate_path(path_string) {
|
|
206
|
+
return YerbaGetResult {
|
|
207
|
+
is_list: false,
|
|
208
|
+
node_type: YerbaNodeType::NotFound,
|
|
209
|
+
single: YerbaTypedValue {
|
|
210
|
+
text: ptr::null_mut(),
|
|
211
|
+
value_type: YerbaValueType::Null,
|
|
212
|
+
},
|
|
213
|
+
list: YerbaTypedList {
|
|
214
|
+
json: ptr::null_mut(),
|
|
215
|
+
length: 0,
|
|
216
|
+
},
|
|
217
|
+
key_name: ptr::null_mut(),
|
|
218
|
+
key_location: EMPTY_LOCATION,
|
|
219
|
+
location: EMPTY_LOCATION,
|
|
220
|
+
error: CString::new(e.to_string()).unwrap_or_default().into_raw(),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let source = document.to_string();
|
|
225
|
+
|
|
226
|
+
let (location, key_text, key_location) = match document.navigate(path_string) {
|
|
227
|
+
Ok(node) => {
|
|
228
|
+
let range = node.text_range();
|
|
229
|
+
let location = compute_location(&source, range.start().into(), range.end().into());
|
|
230
|
+
|
|
231
|
+
let (key_text, key_location) = node
|
|
232
|
+
.parent()
|
|
233
|
+
.and_then(|parent| {
|
|
234
|
+
use rowan::ast::AstNode;
|
|
235
|
+
use yaml_parser::ast::BlockMapEntry;
|
|
236
|
+
|
|
237
|
+
BlockMapEntry::cast(parent).and_then(|entry| {
|
|
238
|
+
entry.key().and_then(|key_node| {
|
|
239
|
+
let key_text = crate::syntax::extract_scalar_text(key_node.syntax())?;
|
|
240
|
+
let key_range = key_node.syntax().text_range();
|
|
241
|
+
let key_location = compute_location(&source, key_range.start().into(), key_range.end().into());
|
|
242
|
+
|
|
243
|
+
Some((key_text, key_location))
|
|
244
|
+
})
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
.map(|(name, location)| (Some(name), location))
|
|
248
|
+
.unwrap_or((None, EMPTY_LOCATION));
|
|
249
|
+
|
|
250
|
+
(location, key_text, key_location)
|
|
251
|
+
}
|
|
252
|
+
Err(_) => (EMPTY_LOCATION, None, EMPTY_LOCATION),
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
let key_name_pointer = key_text
|
|
256
|
+
.map(|name| CString::new(name).unwrap_or_default().into_raw())
|
|
257
|
+
.unwrap_or(ptr::null_mut());
|
|
258
|
+
|
|
259
|
+
if selector.has_wildcard() {
|
|
260
|
+
let values = document.get_all_typed(path_string);
|
|
261
|
+
|
|
262
|
+
let typed: Vec<serde_json::Value> = values
|
|
263
|
+
.iter()
|
|
264
|
+
.map(|serde_value| {
|
|
265
|
+
serde_json::json!({
|
|
266
|
+
"text": serde_value.text,
|
|
267
|
+
"type": detect_yaml_type(serde_value) as u8
|
|
268
|
+
})
|
|
269
|
+
})
|
|
270
|
+
.collect();
|
|
271
|
+
|
|
272
|
+
let json = serde_json::to_string(&typed).unwrap_or_else(|_| "[]".to_string());
|
|
273
|
+
let length = values.len();
|
|
274
|
+
|
|
275
|
+
YerbaGetResult {
|
|
276
|
+
is_list: true,
|
|
277
|
+
node_type: YerbaNodeType::Sequence,
|
|
278
|
+
single: YerbaTypedValue {
|
|
279
|
+
text: ptr::null_mut(),
|
|
280
|
+
value_type: YerbaValueType::Null,
|
|
281
|
+
},
|
|
282
|
+
list: YerbaTypedList {
|
|
283
|
+
json: CString::new(json).unwrap_or_default().into_raw(),
|
|
284
|
+
length,
|
|
285
|
+
},
|
|
286
|
+
location,
|
|
287
|
+
key_name: key_name_pointer,
|
|
288
|
+
key_location,
|
|
289
|
+
error: ptr::null_mut(),
|
|
290
|
+
}
|
|
291
|
+
} else {
|
|
292
|
+
match document.get_typed(path_string) {
|
|
293
|
+
Some(scalar) => {
|
|
294
|
+
let vtype = detect_yaml_type(&scalar);
|
|
295
|
+
|
|
296
|
+
YerbaGetResult {
|
|
297
|
+
is_list: false,
|
|
298
|
+
node_type: YerbaNodeType::Scalar,
|
|
299
|
+
single: YerbaTypedValue {
|
|
300
|
+
text: CString::new(scalar.text).unwrap_or_default().into_raw(),
|
|
301
|
+
value_type: vtype,
|
|
302
|
+
},
|
|
303
|
+
list: YerbaTypedList {
|
|
304
|
+
json: ptr::null_mut(),
|
|
305
|
+
length: 0,
|
|
306
|
+
},
|
|
307
|
+
location,
|
|
308
|
+
key_name: key_name_pointer,
|
|
309
|
+
key_location,
|
|
310
|
+
error: ptr::null_mut(),
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
None => {
|
|
315
|
+
use rowan::ast::AstNode;
|
|
316
|
+
use yaml_parser::ast::{BlockMap, BlockSeq};
|
|
317
|
+
|
|
318
|
+
let node_type = match document.navigate(path_string) {
|
|
319
|
+
Ok(node) => {
|
|
320
|
+
if node.children().any(|child| BlockSeq::can_cast(child.kind())) {
|
|
321
|
+
YerbaNodeType::Sequence
|
|
322
|
+
} else if node.children().any(|child| BlockMap::can_cast(child.kind())) {
|
|
323
|
+
YerbaNodeType::Map
|
|
324
|
+
} else if node.descendants().any(|child| BlockSeq::can_cast(child.kind())) {
|
|
325
|
+
YerbaNodeType::Sequence
|
|
326
|
+
} else if node.descendants().any(|child| BlockMap::can_cast(child.kind())) {
|
|
327
|
+
YerbaNodeType::Map
|
|
328
|
+
} else {
|
|
329
|
+
YerbaNodeType::NotFound
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
Err(_) => YerbaNodeType::NotFound,
|
|
333
|
+
};
|
|
334
|
+
|
|
335
|
+
YerbaGetResult {
|
|
336
|
+
is_list: false,
|
|
337
|
+
node_type,
|
|
338
|
+
single: YerbaTypedValue {
|
|
339
|
+
text: ptr::null_mut(),
|
|
340
|
+
value_type: YerbaValueType::Null,
|
|
341
|
+
},
|
|
342
|
+
list: YerbaTypedList {
|
|
343
|
+
json: ptr::null_mut(),
|
|
344
|
+
length: 0,
|
|
345
|
+
},
|
|
346
|
+
location,
|
|
347
|
+
key_name: key_name_pointer,
|
|
348
|
+
key_location,
|
|
349
|
+
error: ptr::null_mut(),
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/// Caller must free with yerba_string_free.
|
|
357
|
+
#[no_mangle]
|
|
358
|
+
pub unsafe extern "C" fn yerba_document_get_value(document: *const Document, path: *const c_char) -> *mut c_char {
|
|
359
|
+
let document = &*document;
|
|
360
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
361
|
+
|
|
362
|
+
match document.get_value(path_string) {
|
|
363
|
+
Some(value) => {
|
|
364
|
+
let json = crate::json::yaml_to_json(&value);
|
|
365
|
+
let json_string = serde_json::to_string(&json).unwrap_or_else(|_| "null".to_string());
|
|
366
|
+
CString::new(json_string).unwrap_or_default().into_raw()
|
|
367
|
+
}
|
|
368
|
+
None => ptr::null_mut(),
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/// Caller must free with yerba_string_free.
|
|
373
|
+
#[no_mangle]
|
|
374
|
+
pub unsafe extern "C" fn yerba_document_get_values(document: *const Document, path: *const c_char) -> *mut c_char {
|
|
375
|
+
let document = &*document;
|
|
376
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
377
|
+
|
|
378
|
+
let values = document.get_values(path_string);
|
|
379
|
+
let json_values: Vec<serde_json::Value> = values.iter().map(crate::json::yaml_to_json).collect();
|
|
380
|
+
let json_string = serde_json::to_string(&json_values).unwrap_or_else(|_| "[]".to_string());
|
|
381
|
+
|
|
382
|
+
CString::new(json_string).unwrap_or_default().into_raw()
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
#[no_mangle]
|
|
386
|
+
pub unsafe extern "C" fn yerba_document_get_quote_style(document: *const Document, path: *const c_char) -> i32 {
|
|
387
|
+
let document = &*document;
|
|
388
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
389
|
+
|
|
390
|
+
match document.get_typed(path_string) {
|
|
391
|
+
Some(scalar) => match scalar.kind {
|
|
392
|
+
SyntaxKind::PLAIN_SCALAR => 0,
|
|
393
|
+
SyntaxKind::SINGLE_QUOTED_SCALAR => 1,
|
|
394
|
+
SyntaxKind::DOUBLE_QUOTED_SCALAR => 2,
|
|
395
|
+
_ => -1,
|
|
396
|
+
},
|
|
397
|
+
|
|
398
|
+
None => -1,
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
#[no_mangle]
|
|
403
|
+
pub unsafe extern "C" fn yerba_document_set_quote_style(
|
|
404
|
+
document: *mut Document,
|
|
405
|
+
path: *const c_char,
|
|
406
|
+
style: i32,
|
|
407
|
+
) -> YerbaResult {
|
|
408
|
+
let document = &mut *document;
|
|
409
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
410
|
+
|
|
411
|
+
let quote_style = match style {
|
|
412
|
+
0 => QuoteStyle::Plain,
|
|
413
|
+
1 => QuoteStyle::Single,
|
|
414
|
+
2 => QuoteStyle::Double,
|
|
415
|
+
_ => return YerbaResult::err("Invalid quote style (use 0=plain, 1=single, 2=double)"),
|
|
416
|
+
};
|
|
417
|
+
|
|
418
|
+
match document.set_scalar_style(path_string, "e_style) {
|
|
419
|
+
Ok(()) => YerbaResult::ok(),
|
|
420
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
#[no_mangle]
|
|
425
|
+
pub unsafe extern "C" fn yerba_document_evaluate_condition(
|
|
426
|
+
document: *const Document,
|
|
427
|
+
parent_path: *const c_char,
|
|
428
|
+
condition: *const c_char,
|
|
429
|
+
) -> bool {
|
|
430
|
+
let document = &*document;
|
|
431
|
+
let parent = CStr::from_ptr(parent_path).to_str().unwrap_or("");
|
|
432
|
+
let cond = CStr::from_ptr(condition).to_str().unwrap_or("");
|
|
433
|
+
document.evaluate_condition(parent, cond)
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
#[no_mangle]
|
|
437
|
+
pub unsafe extern "C" fn yerba_document_exists(document: *const Document, path: *const c_char) -> bool {
|
|
438
|
+
let document = &*document;
|
|
439
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
440
|
+
document.exists(path_string)
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
#[no_mangle]
|
|
444
|
+
pub unsafe extern "C" fn yerba_document_find(
|
|
445
|
+
document: *const Document,
|
|
446
|
+
path: *const c_char,
|
|
447
|
+
condition: *const c_char,
|
|
448
|
+
select: *const c_char,
|
|
449
|
+
) -> *mut c_char {
|
|
450
|
+
let document = &*document;
|
|
451
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
452
|
+
|
|
453
|
+
let condition_str = if condition.is_null() {
|
|
454
|
+
None
|
|
455
|
+
} else {
|
|
456
|
+
CStr::from_ptr(condition).to_str().ok()
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
let _select_string = if select.is_null() {
|
|
460
|
+
None
|
|
461
|
+
} else {
|
|
462
|
+
CStr::from_ptr(select).to_str().ok()
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
let values = match condition_str {
|
|
466
|
+
Some(cond) => document.filter(path_string, cond),
|
|
467
|
+
None => document.get_values(path_string),
|
|
468
|
+
};
|
|
469
|
+
|
|
470
|
+
let select_fields: Option<Vec<&str>> = _select_string.map(|s| s.split(',').collect());
|
|
471
|
+
|
|
472
|
+
let mut results: Vec<serde_json::Value> = Vec::new();
|
|
473
|
+
|
|
474
|
+
for value in &values {
|
|
475
|
+
match &select_fields {
|
|
476
|
+
Some(fields) => {
|
|
477
|
+
let mut result = serde_json::Map::new();
|
|
478
|
+
|
|
479
|
+
for field in fields {
|
|
480
|
+
let json_value = crate::json::resolve_select_field(value, field);
|
|
481
|
+
let json_key = crate::json::select_field_key(field);
|
|
482
|
+
|
|
483
|
+
result.insert(json_key, json_value);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
results.push(serde_json::Value::Object(result));
|
|
487
|
+
}
|
|
488
|
+
None => {
|
|
489
|
+
results.push(crate::json::yaml_to_json(value));
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
let json = serde_json::to_string_pretty(&results).unwrap_or_else(|_| "[]".to_string());
|
|
495
|
+
CString::new(json).unwrap_or_default().into_raw()
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
#[no_mangle]
|
|
499
|
+
pub unsafe extern "C" fn yerba_document_set(
|
|
500
|
+
document: *mut Document,
|
|
501
|
+
path: *const c_char,
|
|
502
|
+
value: *const c_char,
|
|
503
|
+
value_type: YerbaValueType,
|
|
504
|
+
) -> YerbaResult {
|
|
505
|
+
let document = &mut *document;
|
|
506
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
507
|
+
let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
|
|
508
|
+
|
|
509
|
+
let result = match value_type {
|
|
510
|
+
YerbaValueType::String => document.set(path_string, value_string),
|
|
511
|
+
_ => document.set_plain(path_string, value_string),
|
|
512
|
+
};
|
|
513
|
+
|
|
514
|
+
match result {
|
|
515
|
+
Ok(()) => YerbaResult::ok(),
|
|
516
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
#[no_mangle]
|
|
521
|
+
pub unsafe extern "C" fn yerba_document_insert(
|
|
522
|
+
document: *mut Document,
|
|
523
|
+
path: *const c_char,
|
|
524
|
+
value: *const c_char,
|
|
525
|
+
before: *const c_char,
|
|
526
|
+
after: *const c_char,
|
|
527
|
+
at: i64,
|
|
528
|
+
) -> YerbaResult {
|
|
529
|
+
let document = &mut *document;
|
|
530
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
531
|
+
let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
|
|
532
|
+
|
|
533
|
+
let position = if at >= 0 {
|
|
534
|
+
InsertPosition::At(at as usize)
|
|
535
|
+
} else if !before.is_null() {
|
|
536
|
+
let target = CStr::from_ptr(before).to_str().unwrap_or("");
|
|
537
|
+
InsertPosition::Before(target.to_string())
|
|
538
|
+
} else if !after.is_null() {
|
|
539
|
+
let target = CStr::from_ptr(after).to_str().unwrap_or("");
|
|
540
|
+
InsertPosition::After(target.to_string())
|
|
541
|
+
} else {
|
|
542
|
+
InsertPosition::Last
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
match document.insert_into(path_string, value_string, position) {
|
|
546
|
+
Ok(()) => YerbaResult::ok(),
|
|
547
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
#[no_mangle]
|
|
552
|
+
pub unsafe extern "C" fn yerba_document_insert_object(
|
|
553
|
+
document: *mut Document,
|
|
554
|
+
path: *const c_char,
|
|
555
|
+
json: *const c_char,
|
|
556
|
+
before: *const c_char,
|
|
557
|
+
after: *const c_char,
|
|
558
|
+
at: i64,
|
|
559
|
+
) -> YerbaResult {
|
|
560
|
+
let document = &mut *document;
|
|
561
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
562
|
+
let json_string = CStr::from_ptr(json).to_str().unwrap_or("");
|
|
563
|
+
|
|
564
|
+
let json_value: serde_json::Value = match serde_json::from_str(json_string) {
|
|
565
|
+
Ok(v) => v,
|
|
566
|
+
Err(e) => return YerbaResult::err(&format!("Invalid JSON: {}", e)),
|
|
567
|
+
};
|
|
568
|
+
|
|
569
|
+
let try_paths = if path_string.is_empty() {
|
|
570
|
+
vec!["[]".to_string(), "[0]".to_string()]
|
|
571
|
+
} else {
|
|
572
|
+
vec![format!("{}[]", path_string), format!("{}[0]", path_string)]
|
|
573
|
+
};
|
|
574
|
+
|
|
575
|
+
let mut quote_style = QuoteStyle::Plain;
|
|
576
|
+
|
|
577
|
+
'outer: for try_path in &try_paths {
|
|
578
|
+
for scalar in document.get_all_typed(try_path) {
|
|
579
|
+
if scalar.kind == SyntaxKind::DOUBLE_QUOTED_SCALAR {
|
|
580
|
+
quote_style = QuoteStyle::Double;
|
|
581
|
+
break 'outer;
|
|
582
|
+
} else if scalar.kind == SyntaxKind::SINGLE_QUOTED_SCALAR {
|
|
583
|
+
quote_style = QuoteStyle::Single;
|
|
584
|
+
break 'outer;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
if quote_style == QuoteStyle::Plain {
|
|
590
|
+
if let Some(serde_yaml::Value::Sequence(seq)) = document.get_value(path_string).as_ref() {
|
|
591
|
+
if let Some(serde_yaml::Value::Mapping(map)) = seq.first() {
|
|
592
|
+
if let Some((serde_yaml::Value::String(key_name), _)) = map.iter().next() {
|
|
593
|
+
let deep_path = if path_string.is_empty() {
|
|
594
|
+
format!("[].{}", key_name)
|
|
595
|
+
} else {
|
|
596
|
+
format!("{}[].{}", path_string, key_name)
|
|
597
|
+
};
|
|
598
|
+
|
|
599
|
+
for scalar in document.get_all_typed(&deep_path) {
|
|
600
|
+
if scalar.kind == SyntaxKind::DOUBLE_QUOTED_SCALAR {
|
|
601
|
+
quote_style = QuoteStyle::Double;
|
|
602
|
+
break;
|
|
603
|
+
} else if scalar.kind == SyntaxKind::SINGLE_QUOTED_SCALAR {
|
|
604
|
+
quote_style = QuoteStyle::Single;
|
|
605
|
+
break;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
let yaml_text = crate::yaml_writer::json_to_yaml_text(&json_value, "e_style, 0);
|
|
614
|
+
|
|
615
|
+
let position = if at >= 0 {
|
|
616
|
+
InsertPosition::At(at as usize)
|
|
617
|
+
} else if !before.is_null() {
|
|
618
|
+
let target = CStr::from_ptr(before).to_str().unwrap_or("");
|
|
619
|
+
InsertPosition::Before(target.to_string())
|
|
620
|
+
} else if !after.is_null() {
|
|
621
|
+
let target = CStr::from_ptr(after).to_str().unwrap_or("");
|
|
622
|
+
InsertPosition::After(target.to_string())
|
|
623
|
+
} else {
|
|
624
|
+
InsertPosition::Last
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
match document.insert_into(path_string, &yaml_text, position) {
|
|
628
|
+
Ok(()) => YerbaResult::ok(),
|
|
629
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
#[no_mangle]
|
|
634
|
+
pub unsafe extern "C" fn yerba_document_delete(document: *mut Document, path: *const c_char) -> YerbaResult {
|
|
635
|
+
let document = &mut *document;
|
|
636
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
637
|
+
|
|
638
|
+
match document.delete(path_string) {
|
|
639
|
+
Ok(()) => YerbaResult::ok(),
|
|
640
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
#[no_mangle]
|
|
645
|
+
pub unsafe extern "C" fn yerba_document_remove(
|
|
646
|
+
document: *mut Document,
|
|
647
|
+
path: *const c_char,
|
|
648
|
+
value: *const c_char,
|
|
649
|
+
) -> YerbaResult {
|
|
650
|
+
let document = &mut *document;
|
|
651
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
652
|
+
let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
|
|
653
|
+
|
|
654
|
+
match document.remove(path_string, value_string) {
|
|
655
|
+
Ok(()) => YerbaResult::ok(),
|
|
656
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
#[no_mangle]
|
|
661
|
+
pub unsafe extern "C" fn yerba_document_remove_at(
|
|
662
|
+
document: *mut Document,
|
|
663
|
+
path: *const c_char,
|
|
664
|
+
index: usize,
|
|
665
|
+
) -> YerbaResult {
|
|
666
|
+
let document = &mut *document;
|
|
667
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
668
|
+
|
|
669
|
+
match document.remove_at(path_string, index) {
|
|
670
|
+
Ok(()) => YerbaResult::ok(),
|
|
671
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
#[no_mangle]
|
|
676
|
+
pub unsafe extern "C" fn yerba_document_rename(
|
|
677
|
+
document: *mut Document,
|
|
678
|
+
source: *const c_char,
|
|
679
|
+
dest: *const c_char,
|
|
680
|
+
) -> YerbaResult {
|
|
681
|
+
let document = &mut *document;
|
|
682
|
+
let source_string = CStr::from_ptr(source).to_str().unwrap_or("");
|
|
683
|
+
let dest_string = CStr::from_ptr(dest).to_str().unwrap_or("");
|
|
684
|
+
|
|
685
|
+
match document.rename(source_string, dest_string) {
|
|
686
|
+
Ok(()) => YerbaResult::ok(),
|
|
687
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
#[no_mangle]
|
|
692
|
+
pub unsafe extern "C" fn yerba_document_sort(
|
|
693
|
+
document: *mut Document,
|
|
694
|
+
path: *const c_char,
|
|
695
|
+
by: *const c_char,
|
|
696
|
+
case_sensitive: bool,
|
|
697
|
+
) -> YerbaResult {
|
|
698
|
+
let document = &mut *document;
|
|
699
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
700
|
+
|
|
701
|
+
let by_string = if by.is_null() {
|
|
702
|
+
None
|
|
703
|
+
} else {
|
|
704
|
+
CStr::from_ptr(by).to_str().ok()
|
|
705
|
+
};
|
|
706
|
+
|
|
707
|
+
let sort_fields: Vec<crate::SortField> = match by_string {
|
|
708
|
+
Some(fields) => fields
|
|
709
|
+
.split(',')
|
|
710
|
+
.map(|field| {
|
|
711
|
+
if let Some(name) = field.strip_suffix(":desc") {
|
|
712
|
+
crate::SortField {
|
|
713
|
+
path: name.to_string(),
|
|
714
|
+
ascending: false,
|
|
715
|
+
}
|
|
716
|
+
} else {
|
|
717
|
+
crate::SortField {
|
|
718
|
+
path: field.to_string(),
|
|
719
|
+
ascending: true,
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
})
|
|
723
|
+
.collect(),
|
|
724
|
+
None => vec![],
|
|
725
|
+
};
|
|
726
|
+
|
|
727
|
+
match document.sort_items(path_string, &sort_fields, case_sensitive) {
|
|
728
|
+
Ok(()) => YerbaResult::ok(),
|
|
729
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
#[no_mangle]
|
|
734
|
+
pub unsafe extern "C" fn yerba_document_sort_keys(
|
|
735
|
+
document: *mut Document,
|
|
736
|
+
path: *const c_char,
|
|
737
|
+
order: *const c_char,
|
|
738
|
+
) -> YerbaResult {
|
|
739
|
+
let document = &mut *document;
|
|
740
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
741
|
+
let order_string = CStr::from_ptr(order).to_str().unwrap_or("");
|
|
742
|
+
let key_order: Vec<&str> = order_string.split(',').collect();
|
|
743
|
+
|
|
744
|
+
match document.sort_keys(path_string, &key_order) {
|
|
745
|
+
Ok(()) => YerbaResult::ok(),
|
|
746
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
#[no_mangle]
|
|
751
|
+
pub unsafe extern "C" fn yerba_document_quote_style(
|
|
752
|
+
document: *mut Document,
|
|
753
|
+
path: *const c_char,
|
|
754
|
+
key_style: *const c_char,
|
|
755
|
+
value_style: *const c_char,
|
|
756
|
+
) -> YerbaResult {
|
|
757
|
+
let document = &mut *document;
|
|
758
|
+
|
|
759
|
+
let path_string = if path.is_null() {
|
|
760
|
+
None
|
|
761
|
+
} else {
|
|
762
|
+
CStr::from_ptr(path).to_str().ok()
|
|
763
|
+
};
|
|
764
|
+
|
|
765
|
+
let key_quote_style = if key_style.is_null() {
|
|
766
|
+
None
|
|
767
|
+
} else {
|
|
768
|
+
CStr::from_ptr(key_style)
|
|
769
|
+
.to_str()
|
|
770
|
+
.ok()
|
|
771
|
+
.and_then(|s| s.parse::<QuoteStyle>().ok())
|
|
772
|
+
};
|
|
773
|
+
|
|
774
|
+
let value_quote_style = if value_style.is_null() {
|
|
775
|
+
None
|
|
776
|
+
} else {
|
|
777
|
+
CStr::from_ptr(value_style)
|
|
778
|
+
.to_str()
|
|
779
|
+
.ok()
|
|
780
|
+
.and_then(|s| s.parse::<QuoteStyle>().ok())
|
|
781
|
+
};
|
|
782
|
+
|
|
783
|
+
if let Some(ref key_style) = key_quote_style {
|
|
784
|
+
if let Err(e) = document.enforce_key_style(key_style, path_string) {
|
|
785
|
+
return YerbaResult::err(&e.to_string());
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
if let Some(ref value_style) = value_quote_style {
|
|
790
|
+
if let Err(e) = document.enforce_quotes_at(value_style, path_string) {
|
|
791
|
+
return YerbaResult::err(&e.to_string());
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
YerbaResult::ok()
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
#[no_mangle]
|
|
799
|
+
pub unsafe extern "C" fn yerba_document_blank_lines(
|
|
800
|
+
document: *mut Document,
|
|
801
|
+
path: *const c_char,
|
|
802
|
+
count: usize,
|
|
803
|
+
) -> YerbaResult {
|
|
804
|
+
let document = &mut *document;
|
|
805
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
806
|
+
|
|
807
|
+
match document.enforce_blank_lines(path_string, count) {
|
|
808
|
+
Ok(()) => YerbaResult::ok(),
|
|
809
|
+
Err(e) => YerbaResult::err(&e.to_string()),
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
#[no_mangle]
|
|
814
|
+
pub unsafe extern "C" fn yerba_document_to_string(document: *const Document) -> *mut c_char {
|
|
815
|
+
let document = &*document;
|
|
816
|
+
let content = document.to_string();
|
|
817
|
+
|
|
818
|
+
CString::new(content).unwrap_or_default().into_raw()
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
#[no_mangle]
|
|
822
|
+
pub unsafe extern "C" fn yerba_string_free(s: *mut c_char) {
|
|
823
|
+
if !s.is_null() {
|
|
824
|
+
drop(CString::from_raw(s));
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
#[no_mangle]
|
|
829
|
+
pub unsafe extern "C" fn yerba_result_free(result: YerbaResult) {
|
|
830
|
+
if !result.error.is_null() {
|
|
831
|
+
drop(CString::from_raw(result.error));
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
#[no_mangle]
|
|
836
|
+
pub unsafe extern "C" fn yerba_get_result_free(result: YerbaGetResult) {
|
|
837
|
+
if !result.single.text.is_null() {
|
|
838
|
+
drop(CString::from_raw(result.single.text));
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
if !result.list.json.is_null() {
|
|
842
|
+
drop(CString::from_raw(result.list.json));
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if !result.key_name.is_null() {
|
|
846
|
+
drop(CString::from_raw(result.key_name));
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
#[no_mangle]
|
|
851
|
+
pub unsafe extern "C" fn yerba_glob_get(glob_pattern: *const c_char, path: *const c_char) -> YerbaTypedList {
|
|
852
|
+
let pattern = CStr::from_ptr(glob_pattern).to_str().unwrap_or("");
|
|
853
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
854
|
+
let selector = Selector::parse(path_string);
|
|
855
|
+
|
|
856
|
+
let files = match glob::glob(pattern) {
|
|
857
|
+
Ok(paths) => paths.filter_map(|p| p.ok()).collect::<Vec<_>>(),
|
|
858
|
+
Err(_) => {
|
|
859
|
+
return YerbaTypedList {
|
|
860
|
+
json: CString::new("[]").unwrap_or_default().into_raw(),
|
|
861
|
+
length: 0,
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
use rayon::prelude::*;
|
|
867
|
+
|
|
868
|
+
let results: Vec<serde_json::Value> = files
|
|
869
|
+
.par_iter()
|
|
870
|
+
.flat_map(|file| {
|
|
871
|
+
let mut file_results = Vec::new();
|
|
872
|
+
|
|
873
|
+
if let Ok(document) = Document::parse_file(file) {
|
|
874
|
+
if selector.has_wildcard() {
|
|
875
|
+
for scalar in document.get_all_typed(path_string) {
|
|
876
|
+
let value_type = detect_yaml_type(&scalar);
|
|
877
|
+
|
|
878
|
+
file_results.push(serde_json::json!({"text": scalar.text, "type": value_type as u8}));
|
|
879
|
+
}
|
|
880
|
+
} else if let Some(scalar) = document.get_typed(path_string) {
|
|
881
|
+
let value_type = detect_yaml_type(&scalar);
|
|
882
|
+
|
|
883
|
+
file_results.push(serde_json::json!({"text": scalar.text, "type": value_type as u8}));
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
file_results
|
|
888
|
+
})
|
|
889
|
+
.collect();
|
|
890
|
+
|
|
891
|
+
let length = results.len();
|
|
892
|
+
let json = serde_json::to_string(&results).unwrap_or_else(|_| "[]".to_string());
|
|
893
|
+
|
|
894
|
+
YerbaTypedList {
|
|
895
|
+
json: CString::new(json).unwrap_or_default().into_raw(),
|
|
896
|
+
length,
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
#[no_mangle]
|
|
901
|
+
pub unsafe extern "C" fn yerba_glob_find(
|
|
902
|
+
glob_pattern: *const c_char,
|
|
903
|
+
path: *const c_char,
|
|
904
|
+
condition: *const c_char,
|
|
905
|
+
select: *const c_char,
|
|
906
|
+
) -> YerbaTypedList {
|
|
907
|
+
let pattern = CStr::from_ptr(glob_pattern).to_str().unwrap_or("");
|
|
908
|
+
let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
|
|
909
|
+
|
|
910
|
+
let condition_string = if condition.is_null() {
|
|
911
|
+
None
|
|
912
|
+
} else {
|
|
913
|
+
CStr::from_ptr(condition).to_str().ok()
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
let _select_string = if select.is_null() {
|
|
917
|
+
None
|
|
918
|
+
} else {
|
|
919
|
+
CStr::from_ptr(select).to_str().ok()
|
|
920
|
+
};
|
|
921
|
+
|
|
922
|
+
let files = match glob::glob(pattern) {
|
|
923
|
+
Ok(paths) => paths.filter_map(|p| p.ok()).collect::<Vec<_>>(),
|
|
924
|
+
Err(_) => {
|
|
925
|
+
return YerbaTypedList {
|
|
926
|
+
json: CString::new("[]").unwrap_or_default().into_raw(),
|
|
927
|
+
length: 0,
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
use rayon::prelude::*;
|
|
933
|
+
|
|
934
|
+
let select_fields: Option<Vec<&str>> = _select_string.map(|s| s.split(',').collect());
|
|
935
|
+
|
|
936
|
+
let all_results: Vec<serde_json::Value> = files
|
|
937
|
+
.par_iter()
|
|
938
|
+
.flat_map(|file| {
|
|
939
|
+
let mut file_results = Vec::new();
|
|
940
|
+
|
|
941
|
+
if let Ok(document) = Document::parse_file(file) {
|
|
942
|
+
let values = match condition_string {
|
|
943
|
+
Some(cond) => document.filter(path_string, cond),
|
|
944
|
+
None => document.get_values(path_string),
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
let file_string = file.to_string_lossy().to_string();
|
|
948
|
+
|
|
949
|
+
for value in &values {
|
|
950
|
+
let mut result = serde_json::Map::new();
|
|
951
|
+
result.insert("__file".to_string(), serde_json::Value::String(file_string.clone()));
|
|
952
|
+
|
|
953
|
+
match &select_fields {
|
|
954
|
+
Some(fields) => {
|
|
955
|
+
for field in fields {
|
|
956
|
+
let json_value = crate::json::resolve_select_field(value, field);
|
|
957
|
+
let json_key = crate::json::select_field_key(field);
|
|
958
|
+
result.insert(json_key, json_value);
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
None => {
|
|
963
|
+
if let serde_yaml::Value::Mapping(map) = value {
|
|
964
|
+
for (key, yaml_value) in map {
|
|
965
|
+
let json_key = match key {
|
|
966
|
+
serde_yaml::Value::String(string) => string.clone(),
|
|
967
|
+
_ => format!("{:?}", key),
|
|
968
|
+
};
|
|
969
|
+
|
|
970
|
+
result.insert(json_key, crate::json::yaml_to_json(yaml_value));
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
file_results.push(serde_json::Value::Object(result));
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
file_results
|
|
981
|
+
})
|
|
982
|
+
.collect();
|
|
983
|
+
|
|
984
|
+
let length = all_results.len();
|
|
985
|
+
let json = serde_json::to_string_pretty(&all_results).unwrap_or_else(|_| "[]".to_string());
|
|
986
|
+
|
|
987
|
+
YerbaTypedList {
|
|
988
|
+
json: CString::new(json).unwrap_or_default().into_raw(),
|
|
989
|
+
length,
|
|
990
|
+
}
|
|
991
|
+
}
|