yerba 0.2.2-aarch64-linux-gnu → 0.4.0-aarch64-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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +167 -12
  3. data/exe/aarch64-linux-gnu/yerba +0 -0
  4. data/ext/yerba/extconf.rb +39 -12
  5. data/ext/yerba/include/yerba.h +21 -10
  6. data/ext/yerba/yerba.c +91 -25
  7. data/lib/yerba/3.2/yerba.so +0 -0
  8. data/lib/yerba/3.3/yerba.so +0 -0
  9. data/lib/yerba/3.4/yerba.so +0 -0
  10. data/lib/yerba/4.0/yerba.so +0 -0
  11. data/lib/yerba/collection.rb +35 -0
  12. data/lib/yerba/document.rb +16 -0
  13. data/lib/yerba/sequence.rb +169 -1
  14. data/lib/yerba/version.rb +1 -1
  15. data/lib/yerba.rb +7 -2
  16. data/rust/Cargo.lock +1 -1
  17. data/rust/Cargo.toml +2 -2
  18. data/rust/cbindgen.toml +1 -0
  19. data/rust/rustfmt.toml +1 -1
  20. data/rust/src/commands/blank_lines.rs +1 -4
  21. data/rust/src/commands/delete.rs +9 -4
  22. data/rust/src/commands/directives.rs +61 -0
  23. data/rust/src/commands/get.rs +52 -26
  24. data/rust/src/commands/insert.rs +8 -4
  25. data/rust/src/commands/mod.rs +71 -9
  26. data/rust/src/commands/move_item.rs +2 -1
  27. data/rust/src/commands/move_key.rs +2 -1
  28. data/rust/src/commands/quote_style.rs +12 -6
  29. data/rust/src/commands/remove.rs +8 -4
  30. data/rust/src/commands/rename.rs +8 -4
  31. data/rust/src/commands/selectors.rs +158 -0
  32. data/rust/src/commands/set.rs +33 -16
  33. data/rust/src/commands/sort.rs +342 -10
  34. data/rust/src/didyoumean.rs +53 -0
  35. data/rust/src/document/condition.rs +139 -0
  36. data/rust/src/document/delete.rs +91 -0
  37. data/rust/src/document/get.rs +262 -0
  38. data/rust/src/document/insert.rs +314 -0
  39. data/rust/src/document/mod.rs +784 -0
  40. data/rust/src/document/set.rs +90 -0
  41. data/rust/src/document/sort.rs +607 -0
  42. data/rust/src/document/style.rs +473 -0
  43. data/rust/src/error.rs +35 -7
  44. data/rust/src/ffi.rs +213 -520
  45. data/rust/src/json.rs +1 -7
  46. data/rust/src/lib.rs +89 -2
  47. data/rust/src/main.rs +2 -0
  48. data/rust/src/quote_style.rs +83 -7
  49. data/rust/src/selector.rs +2 -7
  50. data/rust/src/syntax.rs +41 -21
  51. data/rust/src/yerbafile.rs +39 -18
  52. metadata +13 -3
  53. data/rust/src/document.rs +0 -2237
data/rust/src/ffi.rs CHANGED
@@ -12,10 +12,8 @@ use std::ffi::{CStr, CString};
12
12
  use std::os::raw::c_char;
13
13
  use std::ptr;
14
14
 
15
- use yaml_parser::SyntaxKind;
16
-
17
- use crate::selector::Selector;
18
15
  use crate::syntax::{detect_yaml_type, YerbaValueType};
16
+ use crate::NodeType;
19
17
  use crate::{Document, InsertPosition, QuoteStyle};
20
18
 
21
19
  #[repr(C)]
@@ -52,15 +50,6 @@ pub struct YerbaTypedList {
52
50
  pub length: usize,
53
51
  }
54
52
 
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
53
  #[repr(C)]
65
54
  pub struct YerbaParseResult {
66
55
  pub document: *mut Document,
@@ -80,7 +69,7 @@ pub struct YerbaLocation {
80
69
  #[repr(C)]
81
70
  pub struct YerbaGetResult {
82
71
  pub is_list: bool,
83
- pub node_type: YerbaNodeType,
72
+ pub node_type: NodeType,
84
73
  pub single: YerbaTypedValue,
85
74
  pub list: YerbaTypedList,
86
75
  pub location: YerbaLocation,
@@ -89,6 +78,72 @@ pub struct YerbaGetResult {
89
78
  pub error: *mut c_char,
90
79
  }
91
80
 
81
+ impl YerbaGetResult {
82
+ fn empty() -> Self {
83
+ YerbaGetResult {
84
+ is_list: false,
85
+ node_type: NodeType::NotFound,
86
+ single: YerbaTypedValue {
87
+ text: ptr::null_mut(),
88
+ value_type: YerbaValueType::Null,
89
+ },
90
+ list: YerbaTypedList {
91
+ json: ptr::null_mut(),
92
+ length: 0,
93
+ },
94
+ location: EMPTY_LOCATION,
95
+ key_name: ptr::null_mut(),
96
+ key_location: EMPTY_LOCATION,
97
+ error: ptr::null_mut(),
98
+ }
99
+ }
100
+
101
+ fn with_error(error: &str) -> Self {
102
+ let mut result = Self::empty();
103
+
104
+ result.error = CString::new(error).unwrap_or_default().into_raw();
105
+
106
+ result
107
+ }
108
+
109
+ fn with_location(mut self, location: YerbaLocation, key_name: *mut c_char, key_location: YerbaLocation) -> Self {
110
+ self.location = location;
111
+ self.key_name = key_name;
112
+ self.key_location = key_location;
113
+
114
+ self
115
+ }
116
+
117
+ fn scalar(mut self, text: &str, value_type: YerbaValueType) -> Self {
118
+ self.node_type = NodeType::Scalar;
119
+
120
+ self.single = YerbaTypedValue {
121
+ text: CString::new(text).unwrap_or_default().into_raw(),
122
+ value_type,
123
+ };
124
+
125
+ self
126
+ }
127
+
128
+ fn list(mut self, json: &str, length: usize) -> Self {
129
+ self.is_list = true;
130
+ self.node_type = NodeType::Sequence;
131
+
132
+ self.list = YerbaTypedList {
133
+ json: CString::new(json).unwrap_or_default().into_raw(),
134
+ length,
135
+ };
136
+
137
+ self
138
+ }
139
+
140
+ fn with_node_type(mut self, node_type: NodeType) -> Self {
141
+ self.node_type = node_type;
142
+
143
+ self
144
+ }
145
+ }
146
+
92
147
  #[no_mangle]
93
148
  pub unsafe extern "C" fn yerba_document_parse_file(path: *const c_char) -> YerbaParseResult {
94
149
  if path.is_null() {
@@ -98,19 +153,17 @@ pub unsafe extern "C" fn yerba_document_parse_file(path: *const c_char) -> Yerba
98
153
  };
99
154
  }
100
155
 
101
- let path_string = match CStr::from_ptr(path).to_str() {
156
+ let file_path = match CStr::from_ptr(path).to_str() {
102
157
  Ok(string) => string,
103
158
  Err(e) => {
104
159
  return YerbaParseResult {
105
160
  document: ptr::null_mut(),
106
- error: CString::new(format!("Invalid UTF-8 in path: {}", e))
107
- .unwrap_or_default()
108
- .into_raw(),
161
+ error: CString::new(format!("Invalid UTF-8 in path: {}", e)).unwrap_or_default().into_raw(),
109
162
  }
110
163
  }
111
164
  };
112
165
 
113
- match Document::parse_file(path_string) {
166
+ match Document::parse_file(file_path) {
114
167
  Ok(document) => YerbaParseResult {
115
168
  document: Box::into_raw(Box::new(document)),
116
169
  error: ptr::null_mut(),
@@ -137,9 +190,7 @@ pub unsafe extern "C" fn yerba_document_parse(content: *const c_char) -> YerbaPa
137
190
  Err(e) => {
138
191
  return YerbaParseResult {
139
192
  document: ptr::null_mut(),
140
- error: CString::new(format!("Invalid UTF-8: {}", e))
141
- .unwrap_or_default()
142
- .into_raw(),
193
+ error: CString::new(format!("Invalid UTF-8: {}", e)).unwrap_or_default().into_raw(),
143
194
  }
144
195
  }
145
196
  };
@@ -157,28 +208,6 @@ pub unsafe extern "C" fn yerba_document_parse(content: *const c_char) -> YerbaPa
157
208
  }
158
209
  }
159
210
 
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
211
  const EMPTY_LOCATION: YerbaLocation = YerbaLocation {
183
212
  start_offset: 0,
184
213
  end_offset: 0,
@@ -198,173 +227,71 @@ pub unsafe extern "C" fn yerba_document_free(document: *mut Document) {
198
227
  #[no_mangle]
199
228
  pub unsafe extern "C" fn yerba_document_get(document: *const Document, path: *const c_char) -> YerbaGetResult {
200
229
  let document = &*document;
201
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
202
-
203
- let selector = Selector::parse(path_string);
230
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
204
231
 
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
- };
232
+ if let Err(e) = Document::validate_path(selector_string) {
233
+ return YerbaGetResult::with_error(&e.to_string());
222
234
  }
223
235
 
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
+ let info = document.get_node_info(selector_string);
237
+ let location = location_to_ffi(info.location);
238
+ let key_location = location_to_ffi(info.key_location);
236
239
 
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
240
+ let key_name = info
241
+ .key_name
256
242
  .map(|name| CString::new(name).unwrap_or_default().into_raw())
257
243
  .unwrap_or(ptr::null_mut());
258
244
 
259
- if selector.has_wildcard() {
260
- let values = document.get_all_typed(path_string);
245
+ let base = YerbaGetResult::empty().with_location(location, key_name, key_location);
261
246
 
262
- let typed: Vec<serde_json::Value> = values
247
+ if info.is_list {
248
+ let typed: Vec<serde_json::Value> = info
249
+ .list_values
263
250
  .iter()
264
- .map(|serde_value| {
251
+ .map(|value| {
265
252
  serde_json::json!({
266
- "text": serde_value.text,
267
- "type": detect_yaml_type(serde_value) as u8
253
+ "text": value.text,
254
+ "type": detect_yaml_type(value) as u8
268
255
  })
269
256
  })
270
257
  .collect();
271
258
 
272
259
  let json = serde_json::to_string(&typed).unwrap_or_else(|_| "[]".to_string());
273
- let length = values.len();
274
260
 
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
- }
261
+ base.list(&json, info.list_values.len())
291
262
  } 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
- }
263
+ match info.value {
264
+ Some(scalar) => base.scalar(&scalar.text, detect_yaml_type(&scalar)),
265
+ None => base.with_node_type(info.node_type),
352
266
  }
353
267
  }
354
268
  }
355
269
 
270
+ fn location_to_ffi(location: crate::Location) -> YerbaLocation {
271
+ YerbaLocation {
272
+ start_offset: location.start_offset,
273
+ end_offset: location.end_offset,
274
+ start_line: location.start_line,
275
+ start_column: location.start_column,
276
+ end_line: location.end_line,
277
+ end_column: location.end_column,
278
+ }
279
+ }
280
+
356
281
  /// Caller must free with yerba_string_free.
357
282
  #[no_mangle]
358
283
  pub unsafe extern "C" fn yerba_document_get_value(document: *const Document, path: *const c_char) -> *mut c_char {
359
284
  let document = &*document;
360
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
285
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
361
286
 
362
- match document.get_value(path_string) {
287
+ match document.get_value(selector_string) {
363
288
  Some(value) => {
364
289
  let json = crate::json::yaml_to_json(&value);
365
290
  let json_string = serde_json::to_string(&json).unwrap_or_else(|_| "null".to_string());
291
+
366
292
  CString::new(json_string).unwrap_or_default().into_raw()
367
293
  }
294
+
368
295
  None => ptr::null_mut(),
369
296
  }
370
297
  }
@@ -373,9 +300,9 @@ pub unsafe extern "C" fn yerba_document_get_value(document: *const Document, pat
373
300
  #[no_mangle]
374
301
  pub unsafe extern "C" fn yerba_document_get_values(document: *const Document, path: *const c_char) -> *mut c_char {
375
302
  let document = &*document;
376
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
303
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
377
304
 
378
- let values = document.get_values(path_string);
305
+ let values = document.get_values(selector_string);
379
306
  let json_values: Vec<serde_json::Value> = values.iter().map(crate::json::yaml_to_json).collect();
380
307
  let json_string = serde_json::to_string(&json_values).unwrap_or_else(|_| "[]".to_string());
381
308
 
@@ -383,50 +310,40 @@ pub unsafe extern "C" fn yerba_document_get_values(document: *const Document, pa
383
310
  }
384
311
 
385
312
  #[no_mangle]
386
- pub unsafe extern "C" fn yerba_document_get_quote_style(document: *const Document, path: *const c_char) -> i32 {
313
+ pub unsafe extern "C" fn yerba_document_get_quote_style(document: *const Document, path: *const c_char) -> *mut c_char {
387
314
  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
- },
315
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
316
+
317
+ match document.get_quote_style(selector_string) {
318
+ Some(style) => {
319
+ let ruby_style = style.replace('-', "_");
397
320
 
398
- None => -1,
321
+ CString::new(ruby_style).map(|s| s.into_raw()).unwrap_or(std::ptr::null_mut())
322
+ }
323
+
324
+ None => std::ptr::null_mut(),
399
325
  }
400
326
  }
401
327
 
402
328
  #[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 {
329
+ pub unsafe extern "C" fn yerba_document_set_quote_style(document: *mut Document, path: *const c_char, style: *const c_char) -> YerbaResult {
408
330
  let document = &mut *document;
409
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
331
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
332
+ let style_string = &CStr::from_ptr(style).to_str().unwrap_or("").replace('_', "-");
410
333
 
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)"),
334
+ let quote_style = match style_string.parse::<QuoteStyle>() {
335
+ Ok(style) => style,
336
+ Err(e) => return YerbaResult::err(&e),
416
337
  };
417
338
 
418
- match document.set_scalar_style(path_string, &quote_style) {
419
- Ok(()) => YerbaResult::ok(),
339
+ match document.enforce_quotes_at(&quote_style, Some(selector_string)) {
340
+ Ok(_warnings) => YerbaResult::ok(),
420
341
  Err(e) => YerbaResult::err(&e.to_string()),
421
342
  }
422
343
  }
423
344
 
424
345
  #[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 {
346
+ pub unsafe extern "C" fn yerba_document_evaluate_condition(document: *const Document, parent_path: *const c_char, condition: *const c_char) -> bool {
430
347
  let document = &*document;
431
348
  let parent = CStr::from_ptr(parent_path).to_str().unwrap_or("");
432
349
  let cond = CStr::from_ptr(condition).to_str().unwrap_or("");
@@ -436,62 +353,22 @@ pub unsafe extern "C" fn yerba_document_evaluate_condition(
436
353
  #[no_mangle]
437
354
  pub unsafe extern "C" fn yerba_document_exists(document: *const Document, path: *const c_char) -> bool {
438
355
  let document = &*document;
439
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
440
- document.exists(path_string)
356
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
357
+ document.exists(selector_string)
441
358
  }
442
359
 
443
360
  #[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 {
361
+ pub unsafe extern "C" fn yerba_document_find(document: *const Document, path: *const c_char, condition: *const c_char, select: *const c_char) -> *mut c_char {
450
362
  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();
363
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
478
364
 
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);
365
+ let condition_string = if condition.is_null() { None } else { CStr::from_ptr(condition).to_str().ok() };
482
366
 
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
- }
367
+ let select_string = if select.is_null() { None } else { CStr::from_ptr(select).to_str().ok() };
493
368
 
369
+ let results = document.find_items(selector_string, condition_string, select_string);
494
370
  let json = serde_json::to_string_pretty(&results).unwrap_or_else(|_| "[]".to_string());
371
+
495
372
  CString::new(json).unwrap_or_default().into_raw()
496
373
  }
497
374
 
@@ -501,14 +378,19 @@ pub unsafe extern "C" fn yerba_document_set(
501
378
  path: *const c_char,
502
379
  value: *const c_char,
503
380
  value_type: YerbaValueType,
381
+ all: bool,
504
382
  ) -> YerbaResult {
505
383
  let document = &mut *document;
506
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
384
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
507
385
  let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
508
386
 
509
- let result = match value_type {
510
- YerbaValueType::String => document.set(path_string, value_string),
511
- _ => document.set_plain(path_string, value_string),
387
+ let result = if all {
388
+ document.set_all(selector_string, value_string)
389
+ } else {
390
+ match value_type {
391
+ YerbaValueType::String => document.set(selector_string, value_string),
392
+ _ => document.set_plain(selector_string, value_string),
393
+ }
512
394
  };
513
395
 
514
396
  match result {
@@ -527,7 +409,7 @@ pub unsafe extern "C" fn yerba_document_insert(
527
409
  at: i64,
528
410
  ) -> YerbaResult {
529
411
  let document = &mut *document;
530
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
412
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
531
413
  let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
532
414
 
533
415
  let position = if at >= 0 {
@@ -542,7 +424,7 @@ pub unsafe extern "C" fn yerba_document_insert(
542
424
  InsertPosition::Last
543
425
  };
544
426
 
545
- match document.insert_into(path_string, value_string, position) {
427
+ match document.insert_into(selector_string, value_string, position) {
546
428
  Ok(()) => YerbaResult::ok(),
547
429
  Err(e) => YerbaResult::err(&e.to_string()),
548
430
  }
@@ -558,60 +440,14 @@ pub unsafe extern "C" fn yerba_document_insert_object(
558
440
  at: i64,
559
441
  ) -> YerbaResult {
560
442
  let document = &mut *document;
561
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
443
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
562
444
  let json_string = CStr::from_ptr(json).to_str().unwrap_or("");
563
445
 
564
446
  let json_value: serde_json::Value = match serde_json::from_str(json_string) {
565
- Ok(v) => v,
447
+ Ok(value) => value,
566
448
  Err(e) => return YerbaResult::err(&format!("Invalid JSON: {}", e)),
567
449
  };
568
450
 
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, &quote_style, 0);
614
-
615
451
  let position = if at >= 0 {
616
452
  InsertPosition::At(at as usize)
617
453
  } else if !before.is_null() {
@@ -624,7 +460,7 @@ pub unsafe extern "C" fn yerba_document_insert_object(
624
460
  InsertPosition::Last
625
461
  };
626
462
 
627
- match document.insert_into(path_string, &yaml_text, position) {
463
+ match document.insert_object(selector_string, &json_value, position) {
628
464
  Ok(()) => YerbaResult::ok(),
629
465
  Err(e) => YerbaResult::err(&e.to_string()),
630
466
  }
@@ -633,51 +469,50 @@ pub unsafe extern "C" fn yerba_document_insert_object(
633
469
  #[no_mangle]
634
470
  pub unsafe extern "C" fn yerba_document_delete(document: *mut Document, path: *const c_char) -> YerbaResult {
635
471
  let document = &mut *document;
636
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
472
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
637
473
 
638
- match document.delete(path_string) {
474
+ match document.delete(selector_string) {
639
475
  Ok(()) => YerbaResult::ok(),
640
476
  Err(e) => YerbaResult::err(&e.to_string()),
641
477
  }
642
478
  }
643
479
 
644
480
  #[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 {
481
+ pub unsafe extern "C" fn yerba_document_remove(document: *mut Document, path: *const c_char, value: *const c_char) -> YerbaResult {
650
482
  let document = &mut *document;
651
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
483
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
652
484
  let value_string = CStr::from_ptr(value).to_str().unwrap_or("");
653
485
 
654
- match document.remove(path_string, value_string) {
486
+ match document.remove(selector_string, value_string) {
655
487
  Ok(()) => YerbaResult::ok(),
656
488
  Err(e) => YerbaResult::err(&e.to_string()),
657
489
  }
658
490
  }
659
491
 
660
492
  #[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 {
493
+ pub unsafe extern "C" fn yerba_document_remove_at(document: *mut Document, path: *const c_char, index: usize) -> YerbaResult {
666
494
  let document = &mut *document;
667
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
495
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
668
496
 
669
- match document.remove_at(path_string, index) {
497
+ match document.remove_at(selector_string, index) {
670
498
  Ok(()) => YerbaResult::ok(),
671
499
  Err(e) => YerbaResult::err(&e.to_string()),
672
500
  }
673
501
  }
674
502
 
675
503
  #[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 {
504
+ pub unsafe extern "C" fn yerba_document_move_item(document: *mut Document, path: *const c_char, from: usize, to: usize) -> YerbaResult {
505
+ let document = &mut *document;
506
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
507
+
508
+ match document.move_item(selector_string, from, to) {
509
+ Ok(()) => YerbaResult::ok(),
510
+ Err(e) => YerbaResult::err(&e.to_string()),
511
+ }
512
+ }
513
+
514
+ #[no_mangle]
515
+ pub unsafe extern "C" fn yerba_document_rename(document: *mut Document, source: *const c_char, dest: *const c_char) -> YerbaResult {
681
516
  let document = &mut *document;
682
517
  let source_string = CStr::from_ptr(source).to_str().unwrap_or("");
683
518
  let dest_string = CStr::from_ptr(dest).to_str().unwrap_or("");
@@ -689,59 +524,46 @@ pub unsafe extern "C" fn yerba_document_rename(
689
524
  }
690
525
 
691
526
  #[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 {
527
+ pub unsafe extern "C" fn yerba_document_sort(document: *mut Document, path: *const c_char, by: *const c_char, case_sensitive: bool) -> YerbaResult {
698
528
  let document = &mut *document;
699
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
529
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
700
530
 
701
- let by_string = if by.is_null() {
702
- None
703
- } else {
704
- CStr::from_ptr(by).to_str().ok()
705
- };
531
+ let by_string = if by.is_null() { None } else { CStr::from_ptr(by).to_str().ok() };
706
532
 
707
533
  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(),
534
+ Some(fields) => crate::SortField::parse_list(fields),
724
535
  None => vec![],
725
536
  };
726
537
 
727
- match document.sort_items(path_string, &sort_fields, case_sensitive) {
538
+ match document.sort_items(selector_string, &sort_fields, case_sensitive) {
728
539
  Ok(()) => YerbaResult::ok(),
729
540
  Err(e) => YerbaResult::err(&e.to_string()),
730
541
  }
731
542
  }
732
543
 
733
544
  #[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 {
545
+ pub unsafe extern "C" fn yerba_document_reorder(document: *mut Document, path: *const c_char, by: *const c_char, order_csv: *const c_char) -> YerbaResult {
739
546
  let document = &mut *document;
740
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
547
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
548
+ let by_string = CStr::from_ptr(by).to_str().unwrap_or("");
549
+ let order_string = CStr::from_ptr(order_csv).to_str().unwrap_or("");
550
+
551
+ let desired_order: Vec<&str> = order_string.split(',').map(|s| s.trim()).collect();
552
+
553
+ match document.reorder_items(selector_string, by_string, &desired_order) {
554
+ Ok(()) => YerbaResult::ok(),
555
+ Err(e) => YerbaResult::err(&e.to_string()),
556
+ }
557
+ }
558
+
559
+ #[no_mangle]
560
+ pub unsafe extern "C" fn yerba_document_sort_keys(document: *mut Document, path: *const c_char, order: *const c_char) -> YerbaResult {
561
+ let document = &mut *document;
562
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
741
563
  let order_string = CStr::from_ptr(order).to_str().unwrap_or("");
742
564
  let key_order: Vec<&str> = order_string.split(',').collect();
743
565
 
744
- match document.sort_keys(path_string, &key_order) {
566
+ match document.sort_keys(selector_string, &key_order) {
745
567
  Ok(()) => YerbaResult::ok(),
746
568
  Err(e) => YerbaResult::err(&e.to_string()),
747
569
  }
@@ -756,55 +578,32 @@ pub unsafe extern "C" fn yerba_document_quote_style(
756
578
  ) -> YerbaResult {
757
579
  let document = &mut *document;
758
580
 
759
- let path_string = if path.is_null() {
760
- None
761
- } else {
762
- CStr::from_ptr(path).to_str().ok()
763
- };
581
+ let selector = if path.is_null() { None } else { CStr::from_ptr(path).to_str().ok() };
764
582
 
765
- let key_quote_style = if key_style.is_null() {
583
+ let key = if key_style.is_null() {
766
584
  None
767
585
  } else {
768
- CStr::from_ptr(key_style)
769
- .to_str()
770
- .ok()
771
- .and_then(|s| s.parse::<QuoteStyle>().ok())
586
+ CStr::from_ptr(key_style).to_str().ok().and_then(|s| s.parse::<crate::KeyStyle>().ok())
772
587
  };
773
588
 
774
- let value_quote_style = if value_style.is_null() {
589
+ let value = if value_style.is_null() {
775
590
  None
776
591
  } else {
777
- CStr::from_ptr(value_style)
778
- .to_str()
779
- .ok()
780
- .and_then(|s| s.parse::<QuoteStyle>().ok())
592
+ CStr::from_ptr(value_style).to_str().ok().and_then(|s| s.parse::<QuoteStyle>().ok())
781
593
  };
782
594
 
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
- }
595
+ match document.enforce_quote_style(key.as_ref(), value.as_ref(), selector) {
596
+ Ok(()) => YerbaResult::ok(),
597
+ Err(e) => YerbaResult::err(&e.to_string()),
793
598
  }
794
-
795
- YerbaResult::ok()
796
599
  }
797
600
 
798
601
  #[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 {
602
+ pub unsafe extern "C" fn yerba_document_blank_lines(document: *mut Document, path: *const c_char, count: usize) -> YerbaResult {
804
603
  let document = &mut *document;
805
- let path_string = CStr::from_ptr(path).to_str().unwrap_or("");
604
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
806
605
 
807
- match document.enforce_blank_lines(path_string, count) {
606
+ match document.enforce_blank_lines(selector_string, count) {
808
607
  Ok(()) => YerbaResult::ok(),
809
608
  Err(e) => YerbaResult::err(&e.to_string()),
810
609
  }
@@ -850,42 +649,12 @@ pub unsafe extern "C" fn yerba_get_result_free(result: YerbaGetResult) {
850
649
  #[no_mangle]
851
650
  pub unsafe extern "C" fn yerba_glob_get(glob_pattern: *const c_char, path: *const c_char) -> YerbaTypedList {
852
651
  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();
652
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
653
+ let scalars = crate::glob_get(pattern, selector_string);
872
654
 
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
- })
655
+ let results: Vec<serde_json::Value> = scalars
656
+ .iter()
657
+ .map(|scalar| serde_json::json!({"text": scalar.text, "type": detect_yaml_type(scalar) as u8}))
889
658
  .collect();
890
659
 
891
660
  let length = results.len();
@@ -898,89 +667,13 @@ pub unsafe extern "C" fn yerba_glob_get(glob_pattern: *const c_char, path: *cons
898
667
  }
899
668
 
900
669
  #[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 {
670
+ pub unsafe extern "C" fn yerba_glob_find(glob_pattern: *const c_char, path: *const c_char, condition: *const c_char, select: *const c_char) -> YerbaTypedList {
907
671
  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();
672
+ let selector_string = CStr::from_ptr(path).to_str().unwrap_or("");
673
+ let condition_string = if condition.is_null() { None } else { CStr::from_ptr(condition).to_str().ok() };
674
+ let select_string = if select.is_null() { None } else { CStr::from_ptr(select).to_str().ok() };
983
675
 
676
+ let all_results = crate::glob_find(pattern, selector_string, condition_string, select_string);
984
677
  let length = all_results.len();
985
678
  let json = serde_json::to_string_pretty(&all_results).unwrap_or_else(|_| "[]".to_string());
986
679