]> git.proxmox.com Git - cargo.git/blob - vendor/git2/src/config.rs
New upstream version 0.47.0
[cargo.git] / vendor / git2 / src / config.rs
1 use libc;
2 use std::ffi::CString;
3 use std::marker;
4 use std::path::{Path, PathBuf};
5 use std::ptr;
6 use std::str;
7
8 use crate::util::{self, Binding};
9 use crate::{raw, Buf, ConfigLevel, Error, IntoCString};
10
11 /// A structure representing a git configuration key/value store
12 pub struct Config {
13 raw: *mut raw::git_config,
14 }
15
16 /// A struct representing a certain entry owned by a `Config` instance.
17 ///
18 /// An entry has a name, a value, and a level it applies to.
19 pub struct ConfigEntry<'cfg> {
20 raw: *mut raw::git_config_entry,
21 _marker: marker::PhantomData<&'cfg Config>,
22 owned: bool,
23 }
24
25 /// An iterator over the `ConfigEntry` values of a `Config` structure.
26 pub struct ConfigEntries<'cfg> {
27 raw: *mut raw::git_config_iterator,
28 _marker: marker::PhantomData<&'cfg Config>,
29 }
30
31 impl Config {
32 /// Allocate a new configuration object
33 ///
34 /// This object is empty, so you have to add a file to it before you can do
35 /// anything with it.
36 pub fn new() -> Result<Config, Error> {
37 crate::init();
38 let mut raw = ptr::null_mut();
39 unsafe {
40 try_call!(raw::git_config_new(&mut raw));
41 Ok(Binding::from_raw(raw))
42 }
43 }
44
45 /// Create a new config instance containing a single on-disk file
46 pub fn open(path: &Path) -> Result<Config, Error> {
47 crate::init();
48 let mut raw = ptr::null_mut();
49 // Normal file path OK (does not need Windows conversion).
50 let path = path.into_c_string()?;
51 unsafe {
52 try_call!(raw::git_config_open_ondisk(&mut raw, path));
53 Ok(Binding::from_raw(raw))
54 }
55 }
56
57 /// Open the global, XDG and system configuration files
58 ///
59 /// Utility wrapper that finds the global, XDG and system configuration
60 /// files and opens them into a single prioritized config object that can
61 /// be used when accessing default config data outside a repository.
62 pub fn open_default() -> Result<Config, Error> {
63 crate::init();
64 let mut raw = ptr::null_mut();
65 unsafe {
66 try_call!(raw::git_config_open_default(&mut raw));
67 Ok(Binding::from_raw(raw))
68 }
69 }
70
71 /// Locate the path to the global configuration file
72 ///
73 /// The user or global configuration file is usually located in
74 /// `$HOME/.gitconfig`.
75 ///
76 /// This method will try to guess the full path to that file, if the file
77 /// exists. The returned path may be used on any method call to load
78 /// the global configuration file.
79 ///
80 /// This method will not guess the path to the xdg compatible config file
81 /// (`.config/git/config`).
82 pub fn find_global() -> Result<PathBuf, Error> {
83 crate::init();
84 let buf = Buf::new();
85 unsafe {
86 try_call!(raw::git_config_find_global(buf.raw()));
87 }
88 Ok(util::bytes2path(&buf).to_path_buf())
89 }
90
91 /// Locate the path to the system configuration file
92 ///
93 /// If /etc/gitconfig doesn't exist, it will look for %PROGRAMFILES%
94 pub fn find_system() -> Result<PathBuf, Error> {
95 crate::init();
96 let buf = Buf::new();
97 unsafe {
98 try_call!(raw::git_config_find_system(buf.raw()));
99 }
100 Ok(util::bytes2path(&buf).to_path_buf())
101 }
102
103 /// Locate the path to the global xdg compatible configuration file
104 ///
105 /// The xdg compatible configuration file is usually located in
106 /// `$HOME/.config/git/config`.
107 pub fn find_xdg() -> Result<PathBuf, Error> {
108 crate::init();
109 let buf = Buf::new();
110 unsafe {
111 try_call!(raw::git_config_find_xdg(buf.raw()));
112 }
113 Ok(util::bytes2path(&buf).to_path_buf())
114 }
115
116 /// Add an on-disk config file instance to an existing config
117 ///
118 /// The on-disk file pointed at by path will be opened and parsed; it's
119 /// expected to be a native Git config file following the default Git config
120 /// syntax (see man git-config).
121 ///
122 /// Further queries on this config object will access each of the config
123 /// file instances in order (instances with a higher priority level will be
124 /// accessed first).
125 pub fn add_file(&mut self, path: &Path, level: ConfigLevel, force: bool) -> Result<(), Error> {
126 // Normal file path OK (does not need Windows conversion).
127 let path = path.into_c_string()?;
128 unsafe {
129 try_call!(raw::git_config_add_file_ondisk(
130 self.raw,
131 path,
132 level,
133 ptr::null(),
134 force
135 ));
136 Ok(())
137 }
138 }
139
140 /// Delete a config variable from the config file with the highest level
141 /// (usually the local one).
142 pub fn remove(&mut self, name: &str) -> Result<(), Error> {
143 let name = CString::new(name)?;
144 unsafe {
145 try_call!(raw::git_config_delete_entry(self.raw, name));
146 Ok(())
147 }
148 }
149
150 /// Remove multivar config variables in the config file with the highest level (usually the
151 /// local one).
152 pub fn remove_multivar(&mut self, name: &str, regexp: &str) -> Result<(), Error> {
153 let name = CString::new(name)?;
154 let regexp = CString::new(regexp)?;
155 unsafe {
156 try_call!(raw::git_config_delete_multivar(self.raw, name, regexp));
157 }
158 Ok(())
159 }
160
161 /// Get the value of a boolean config variable.
162 ///
163 /// All config files will be looked into, in the order of their defined
164 /// level. A higher level means a higher priority. The first occurrence of
165 /// the variable will be returned here.
166 pub fn get_bool(&self, name: &str) -> Result<bool, Error> {
167 let mut out = 0 as libc::c_int;
168 let name = CString::new(name)?;
169 unsafe {
170 try_call!(raw::git_config_get_bool(&mut out, &*self.raw, name));
171 }
172 Ok(out != 0)
173 }
174
175 /// Get the value of an integer config variable.
176 ///
177 /// All config files will be looked into, in the order of their defined
178 /// level. A higher level means a higher priority. The first occurrence of
179 /// the variable will be returned here.
180 pub fn get_i32(&self, name: &str) -> Result<i32, Error> {
181 let mut out = 0i32;
182 let name = CString::new(name)?;
183 unsafe {
184 try_call!(raw::git_config_get_int32(&mut out, &*self.raw, name));
185 }
186 Ok(out)
187 }
188
189 /// Get the value of an integer config variable.
190 ///
191 /// All config files will be looked into, in the order of their defined
192 /// level. A higher level means a higher priority. The first occurrence of
193 /// the variable will be returned here.
194 pub fn get_i64(&self, name: &str) -> Result<i64, Error> {
195 let mut out = 0i64;
196 let name = CString::new(name)?;
197 unsafe {
198 try_call!(raw::git_config_get_int64(&mut out, &*self.raw, name));
199 }
200 Ok(out)
201 }
202
203 /// Get the value of a string config variable.
204 ///
205 /// This is the same as `get_bytes` except that it may return `Err` if
206 /// the bytes are not valid utf-8.
207 pub fn get_str(&self, name: &str) -> Result<&str, Error> {
208 str::from_utf8(self.get_bytes(name)?)
209 .map_err(|_| Error::from_str("configuration value is not valid utf8"))
210 }
211
212 /// Get the value of a string config variable as a byte slice.
213 ///
214 /// This method will return an error if this `Config` is not a snapshot.
215 pub fn get_bytes(&self, name: &str) -> Result<&[u8], Error> {
216 let mut ret = ptr::null();
217 let name = CString::new(name)?;
218 unsafe {
219 try_call!(raw::git_config_get_string(&mut ret, &*self.raw, name));
220 Ok(crate::opt_bytes(self, ret).unwrap())
221 }
222 }
223
224 /// Get the value of a string config variable as an owned string.
225 ///
226 /// An error will be returned if the config value is not valid utf-8.
227 pub fn get_string(&self, name: &str) -> Result<String, Error> {
228 let ret = Buf::new();
229 let name = CString::new(name)?;
230 unsafe {
231 try_call!(raw::git_config_get_string_buf(ret.raw(), self.raw, name));
232 }
233 str::from_utf8(&ret)
234 .map(|s| s.to_string())
235 .map_err(|_| Error::from_str("configuration value is not valid utf8"))
236 }
237
238 /// Get the value of a path config variable as an owned .
239 pub fn get_path(&self, name: &str) -> Result<PathBuf, Error> {
240 let ret = Buf::new();
241 let name = CString::new(name)?;
242 unsafe {
243 try_call!(raw::git_config_get_path(ret.raw(), self.raw, name));
244 }
245 Ok(crate::util::bytes2path(&ret).to_path_buf())
246 }
247
248 /// Get the ConfigEntry for a config variable.
249 pub fn get_entry(&self, name: &str) -> Result<ConfigEntry<'_>, Error> {
250 let mut ret = ptr::null_mut();
251 let name = CString::new(name)?;
252 unsafe {
253 try_call!(raw::git_config_get_entry(&mut ret, self.raw, name));
254 Ok(Binding::from_raw(ret))
255 }
256 }
257
258 /// Iterate over all the config variables
259 ///
260 /// If `glob` is `Some`, then the iterator will only iterate over all
261 /// variables whose name matches the pattern.
262 ///
263 /// # Example
264 ///
265 /// ```
266 /// # #![allow(unstable)]
267 /// use git2::Config;
268 ///
269 /// let cfg = Config::new().unwrap();
270 ///
271 /// for entry in &cfg.entries(None).unwrap() {
272 /// let entry = entry.unwrap();
273 /// println!("{} => {}", entry.name().unwrap(), entry.value().unwrap());
274 /// }
275 /// ```
276 pub fn entries(&self, glob: Option<&str>) -> Result<ConfigEntries<'_>, Error> {
277 let mut ret = ptr::null_mut();
278 unsafe {
279 match glob {
280 Some(s) => {
281 let s = CString::new(s)?;
282 try_call!(raw::git_config_iterator_glob_new(&mut ret, &*self.raw, s));
283 }
284 None => {
285 try_call!(raw::git_config_iterator_new(&mut ret, &*self.raw));
286 }
287 }
288 Ok(Binding::from_raw(ret))
289 }
290 }
291
292 /// Iterate over the values of a multivar
293 ///
294 /// If `regexp` is `Some`, then the iterator will only iterate over all
295 /// values which match the pattern.
296 pub fn multivar(&self, name: &str, regexp: Option<&str>) -> Result<ConfigEntries<'_>, Error> {
297 let mut ret = ptr::null_mut();
298 let name = CString::new(name)?;
299 let regexp = regexp.map(CString::new).transpose()?;
300 unsafe {
301 try_call!(raw::git_config_multivar_iterator_new(
302 &mut ret, &*self.raw, name, regexp
303 ));
304 Ok(Binding::from_raw(ret))
305 }
306 }
307
308 /// Open the global/XDG configuration file according to git's rules
309 ///
310 /// Git allows you to store your global configuration at `$HOME/.config` or
311 /// `$XDG_CONFIG_HOME/git/config`. For backwards compatability, the XDG file
312 /// shouldn't be used unless the use has created it explicitly. With this
313 /// function you'll open the correct one to write to.
314 pub fn open_global(&mut self) -> Result<Config, Error> {
315 let mut raw = ptr::null_mut();
316 unsafe {
317 try_call!(raw::git_config_open_global(&mut raw, self.raw));
318 Ok(Binding::from_raw(raw))
319 }
320 }
321
322 /// Build a single-level focused config object from a multi-level one.
323 ///
324 /// The returned config object can be used to perform get/set/delete
325 /// operations on a single specific level.
326 pub fn open_level(&self, level: ConfigLevel) -> Result<Config, Error> {
327 let mut raw = ptr::null_mut();
328 unsafe {
329 try_call!(raw::git_config_open_level(&mut raw, &*self.raw, level));
330 Ok(Binding::from_raw(raw))
331 }
332 }
333
334 /// Set the value of a boolean config variable in the config file with the
335 /// highest level (usually the local one).
336 pub fn set_bool(&mut self, name: &str, value: bool) -> Result<(), Error> {
337 let name = CString::new(name)?;
338 unsafe {
339 try_call!(raw::git_config_set_bool(self.raw, name, value));
340 }
341 Ok(())
342 }
343
344 /// Set the value of an integer config variable in the config file with the
345 /// highest level (usually the local one).
346 pub fn set_i32(&mut self, name: &str, value: i32) -> Result<(), Error> {
347 let name = CString::new(name)?;
348 unsafe {
349 try_call!(raw::git_config_set_int32(self.raw, name, value));
350 }
351 Ok(())
352 }
353
354 /// Set the value of an integer config variable in the config file with the
355 /// highest level (usually the local one).
356 pub fn set_i64(&mut self, name: &str, value: i64) -> Result<(), Error> {
357 let name = CString::new(name)?;
358 unsafe {
359 try_call!(raw::git_config_set_int64(self.raw, name, value));
360 }
361 Ok(())
362 }
363
364 /// Set the value of an multivar config variable in the config file with the
365 /// highest level (usually the local one).
366 pub fn set_multivar(&mut self, name: &str, regexp: &str, value: &str) -> Result<(), Error> {
367 let name = CString::new(name)?;
368 let regexp = CString::new(regexp)?;
369 let value = CString::new(value)?;
370 unsafe {
371 try_call!(raw::git_config_set_multivar(self.raw, name, regexp, value));
372 }
373 Ok(())
374 }
375
376 /// Set the value of a string config variable in the config file with the
377 /// highest level (usually the local one).
378 pub fn set_str(&mut self, name: &str, value: &str) -> Result<(), Error> {
379 let name = CString::new(name)?;
380 let value = CString::new(value)?;
381 unsafe {
382 try_call!(raw::git_config_set_string(self.raw, name, value));
383 }
384 Ok(())
385 }
386
387 /// Create a snapshot of the configuration
388 ///
389 /// Create a snapshot of the current state of a configuration, which allows
390 /// you to look into a consistent view of the configuration for looking up
391 /// complex values (e.g. a remote, submodule).
392 pub fn snapshot(&mut self) -> Result<Config, Error> {
393 let mut ret = ptr::null_mut();
394 unsafe {
395 try_call!(raw::git_config_snapshot(&mut ret, self.raw));
396 Ok(Binding::from_raw(ret))
397 }
398 }
399
400 /// Parse a string as a bool.
401 /// Interprets "true", "yes", "on", 1, or any non-zero number as true.
402 /// Interprets "false", "no", "off", 0, or an empty string as false.
403 pub fn parse_bool<S: IntoCString>(s: S) -> Result<bool, Error> {
404 let s = s.into_c_string()?;
405 let mut out = 0;
406 crate::init();
407 unsafe {
408 try_call!(raw::git_config_parse_bool(&mut out, s));
409 }
410 Ok(out != 0)
411 }
412
413 /// Parse a string as an i32; handles suffixes like k, M, or G, and
414 /// multiplies by the appropriate power of 1024.
415 pub fn parse_i32<S: IntoCString>(s: S) -> Result<i32, Error> {
416 let s = s.into_c_string()?;
417 let mut out = 0;
418 crate::init();
419 unsafe {
420 try_call!(raw::git_config_parse_int32(&mut out, s));
421 }
422 Ok(out)
423 }
424
425 /// Parse a string as an i64; handles suffixes like k, M, or G, and
426 /// multiplies by the appropriate power of 1024.
427 pub fn parse_i64<S: IntoCString>(s: S) -> Result<i64, Error> {
428 let s = s.into_c_string()?;
429 let mut out = 0;
430 crate::init();
431 unsafe {
432 try_call!(raw::git_config_parse_int64(&mut out, s));
433 }
434 Ok(out)
435 }
436 }
437
438 impl Binding for Config {
439 type Raw = *mut raw::git_config;
440 unsafe fn from_raw(raw: *mut raw::git_config) -> Config {
441 Config { raw: raw }
442 }
443 fn raw(&self) -> *mut raw::git_config {
444 self.raw
445 }
446 }
447
448 impl Drop for Config {
449 fn drop(&mut self) {
450 unsafe { raw::git_config_free(self.raw) }
451 }
452 }
453
454 impl<'cfg> ConfigEntry<'cfg> {
455 /// Gets the name of this entry.
456 ///
457 /// May return `None` if the name is not valid utf-8
458 pub fn name(&self) -> Option<&str> {
459 str::from_utf8(self.name_bytes()).ok()
460 }
461
462 /// Gets the name of this entry as a byte slice.
463 pub fn name_bytes(&self) -> &[u8] {
464 unsafe { crate::opt_bytes(self, (*self.raw).name).unwrap() }
465 }
466
467 /// Gets the value of this entry.
468 ///
469 /// May return `None` if the value is not valid utf-8
470 ///
471 /// # Panics
472 ///
473 /// Panics when no value is defined.
474 pub fn value(&self) -> Option<&str> {
475 str::from_utf8(self.value_bytes()).ok()
476 }
477
478 /// Gets the value of this entry as a byte slice.
479 ///
480 /// # Panics
481 ///
482 /// Panics when no value is defined.
483 pub fn value_bytes(&self) -> &[u8] {
484 unsafe { crate::opt_bytes(self, (*self.raw).value).unwrap() }
485 }
486
487 /// Returns `true` when a value is defined otherwise `false`.
488 ///
489 /// No value defined is a short-hand to represent a Boolean `true`.
490 pub fn has_value(&self) -> bool {
491 unsafe { !(*self.raw).value.is_null() }
492 }
493
494 /// Gets the configuration level of this entry.
495 pub fn level(&self) -> ConfigLevel {
496 unsafe { ConfigLevel::from_raw((*self.raw).level) }
497 }
498
499 /// Depth of includes where this variable was found
500 pub fn include_depth(&self) -> u32 {
501 unsafe { (*self.raw).include_depth as u32 }
502 }
503 }
504
505 impl<'cfg> Binding for ConfigEntry<'cfg> {
506 type Raw = *mut raw::git_config_entry;
507
508 unsafe fn from_raw(raw: *mut raw::git_config_entry) -> ConfigEntry<'cfg> {
509 ConfigEntry {
510 raw: raw,
511 _marker: marker::PhantomData,
512 owned: true,
513 }
514 }
515 fn raw(&self) -> *mut raw::git_config_entry {
516 self.raw
517 }
518 }
519
520 impl<'cfg> Binding for ConfigEntries<'cfg> {
521 type Raw = *mut raw::git_config_iterator;
522
523 unsafe fn from_raw(raw: *mut raw::git_config_iterator) -> ConfigEntries<'cfg> {
524 ConfigEntries {
525 raw: raw,
526 _marker: marker::PhantomData,
527 }
528 }
529 fn raw(&self) -> *mut raw::git_config_iterator {
530 self.raw
531 }
532 }
533
534 // entries are only valid until the iterator is freed, so this impl is for
535 // `&'b T` instead of `T` to have a lifetime to tie them to.
536 //
537 // It's also not implemented for `&'b mut T` so we can have multiple entries
538 // (ok).
539 impl<'cfg, 'b> Iterator for &'b ConfigEntries<'cfg> {
540 type Item = Result<ConfigEntry<'b>, Error>;
541 fn next(&mut self) -> Option<Result<ConfigEntry<'b>, Error>> {
542 let mut raw = ptr::null_mut();
543 unsafe {
544 try_call_iter!(raw::git_config_next(&mut raw, self.raw));
545 Some(Ok(ConfigEntry {
546 owned: false,
547 raw: raw,
548 _marker: marker::PhantomData,
549 }))
550 }
551 }
552 }
553
554 impl<'cfg> Drop for ConfigEntries<'cfg> {
555 fn drop(&mut self) {
556 unsafe { raw::git_config_iterator_free(self.raw) }
557 }
558 }
559
560 impl<'cfg> Drop for ConfigEntry<'cfg> {
561 fn drop(&mut self) {
562 if self.owned {
563 unsafe { raw::git_config_entry_free(self.raw) }
564 }
565 }
566 }
567
568 #[cfg(test)]
569 mod tests {
570 use std::fs::File;
571 use tempfile::TempDir;
572
573 use crate::Config;
574
575 #[test]
576 fn smoke() {
577 let _cfg = Config::new().unwrap();
578 let _ = Config::find_global();
579 let _ = Config::find_system();
580 let _ = Config::find_xdg();
581 }
582
583 #[test]
584 fn persisted() {
585 let td = TempDir::new().unwrap();
586 let path = td.path().join("foo");
587 File::create(&path).unwrap();
588
589 let mut cfg = Config::open(&path).unwrap();
590 assert!(cfg.get_bool("foo.bar").is_err());
591 cfg.set_bool("foo.k1", true).unwrap();
592 cfg.set_i32("foo.k2", 1).unwrap();
593 cfg.set_i64("foo.k3", 2).unwrap();
594 cfg.set_str("foo.k4", "bar").unwrap();
595 cfg.snapshot().unwrap();
596 drop(cfg);
597
598 let cfg = Config::open(&path).unwrap().snapshot().unwrap();
599 assert_eq!(cfg.get_bool("foo.k1").unwrap(), true);
600 assert_eq!(cfg.get_i32("foo.k2").unwrap(), 1);
601 assert_eq!(cfg.get_i64("foo.k3").unwrap(), 2);
602 assert_eq!(cfg.get_str("foo.k4").unwrap(), "bar");
603
604 for entry in &cfg.entries(None).unwrap() {
605 let entry = entry.unwrap();
606 entry.name();
607 entry.value();
608 entry.level();
609 }
610 }
611
612 #[test]
613 fn multivar() {
614 let td = TempDir::new().unwrap();
615 let path = td.path().join("foo");
616 File::create(&path).unwrap();
617
618 let mut cfg = Config::open(&path).unwrap();
619 cfg.set_multivar("foo.bar", "^$", "baz").unwrap();
620 cfg.set_multivar("foo.bar", "^$", "qux").unwrap();
621 cfg.set_multivar("foo.bar", "^$", "quux").unwrap();
622 cfg.set_multivar("foo.baz", "^$", "oki").unwrap();
623
624 // `entries` filters by name
625 let mut entries: Vec<String> = cfg
626 .entries(Some("foo.bar"))
627 .unwrap()
628 .into_iter()
629 .map(|entry| entry.unwrap().value().unwrap().into())
630 .collect();
631 entries.sort();
632 assert_eq!(entries, ["baz", "quux", "qux"]);
633
634 // which is the same as `multivar` without a regex
635 let mut multivals: Vec<String> = cfg
636 .multivar("foo.bar", None)
637 .unwrap()
638 .into_iter()
639 .map(|entry| entry.unwrap().value().unwrap().into())
640 .collect();
641 multivals.sort();
642 assert_eq!(multivals, entries);
643
644 // yet _with_ a regex, `multivar` filters by value
645 let mut quxish: Vec<String> = cfg
646 .multivar("foo.bar", Some("qu.*x"))
647 .unwrap()
648 .into_iter()
649 .map(|entry| entry.unwrap().value().unwrap().into())
650 .collect();
651 quxish.sort();
652 assert_eq!(quxish, ["quux", "qux"]);
653
654 cfg.remove_multivar("foo.bar", ".*").unwrap();
655
656 assert_eq!(cfg.entries(Some("foo.bar")).unwrap().count(), 0);
657 assert_eq!(cfg.multivar("foo.bar", None).unwrap().count(), 0);
658 }
659
660 #[test]
661 fn parse() {
662 assert_eq!(Config::parse_bool("").unwrap(), false);
663 assert_eq!(Config::parse_bool("false").unwrap(), false);
664 assert_eq!(Config::parse_bool("no").unwrap(), false);
665 assert_eq!(Config::parse_bool("off").unwrap(), false);
666 assert_eq!(Config::parse_bool("0").unwrap(), false);
667
668 assert_eq!(Config::parse_bool("true").unwrap(), true);
669 assert_eq!(Config::parse_bool("yes").unwrap(), true);
670 assert_eq!(Config::parse_bool("on").unwrap(), true);
671 assert_eq!(Config::parse_bool("1").unwrap(), true);
672 assert_eq!(Config::parse_bool("42").unwrap(), true);
673
674 assert!(Config::parse_bool(" ").is_err());
675 assert!(Config::parse_bool("some-string").is_err());
676 assert!(Config::parse_bool("-").is_err());
677
678 assert_eq!(Config::parse_i32("0").unwrap(), 0);
679 assert_eq!(Config::parse_i32("1").unwrap(), 1);
680 assert_eq!(Config::parse_i32("100").unwrap(), 100);
681 assert_eq!(Config::parse_i32("-1").unwrap(), -1);
682 assert_eq!(Config::parse_i32("-100").unwrap(), -100);
683 assert_eq!(Config::parse_i32("1k").unwrap(), 1024);
684 assert_eq!(Config::parse_i32("4k").unwrap(), 4096);
685 assert_eq!(Config::parse_i32("1M").unwrap(), 1048576);
686 assert_eq!(Config::parse_i32("1G").unwrap(), 1024 * 1024 * 1024);
687
688 assert_eq!(Config::parse_i64("0").unwrap(), 0);
689 assert_eq!(Config::parse_i64("1").unwrap(), 1);
690 assert_eq!(Config::parse_i64("100").unwrap(), 100);
691 assert_eq!(Config::parse_i64("-1").unwrap(), -1);
692 assert_eq!(Config::parse_i64("-100").unwrap(), -100);
693 assert_eq!(Config::parse_i64("1k").unwrap(), 1024);
694 assert_eq!(Config::parse_i64("4k").unwrap(), 4096);
695 assert_eq!(Config::parse_i64("1M").unwrap(), 1048576);
696 assert_eq!(Config::parse_i64("1G").unwrap(), 1024 * 1024 * 1024);
697 assert_eq!(Config::parse_i64("100G").unwrap(), 100 * 1024 * 1024 * 1024);
698 }
699 }