From a177d95499988ff2b8540e5c6dead8ce09b1a7d1 Mon Sep 17 00:00:00 2001 From: Yehyoung Kang Date: Sun, 9 Feb 2025 18:08:18 +0900 Subject: [PATCH] feat: Support formatting hex/oct/bin integers Add methods that create `Formatted` in hexadecimal, octal, and binary representation. In accordance with TOML 1.0 spec, these forms can be created only if the integer is nonnegative. For hexadecimal, it is possible to create either uppercase or lowercase representation. This commit does not change the AST and should be fully backwards- compatible. --- crates/toml_edit/src/repr.rs | 58 ++++++++++++++++++++++++ crates/toml_edit/tests/testsuite/edit.rs | 31 ++++++++++++- 2 files changed, 88 insertions(+), 1 deletion(-) diff --git a/crates/toml_edit/src/repr.rs b/crates/toml_edit/src/repr.rs index cae7cac32..7448e2ebc 100644 --- a/crates/toml_edit/src/repr.rs +++ b/crates/toml_edit/src/repr.rs @@ -90,6 +90,64 @@ where } } +impl Formatted { + /// Creates a new hexadecimal (uppercase) formatted integer value. + /// Returns `None` if the `value` is negative. + pub fn new_hex_upper(value: i64) -> Option { + if value >= 0 { + Some(Self { + value, + repr: Some(Repr::new_unchecked(format!("{:#X}", value))), + decor: Default::default(), + }) + } else { + None + } + } + + /// Creates a new hexadecimal (lowercase) formatted integer value. + /// Returns `None` if the `value` is negative. + pub fn new_hex_lower(value: i64) -> Option { + if value >= 0 { + Some(Self { + value, + repr: Some(Repr::new_unchecked(format!("{:#x}", value))), + decor: Default::default(), + }) + } else { + None + } + } + + /// Creates a new octal formatted integer value. + /// Returns `None` if the `value` is negative. + pub fn new_oct(value: i64) -> Option { + if value >= 0 { + Some(Self { + value, + repr: Some(Repr::new_unchecked(format!("{:#o}", value))), + decor: Default::default(), + }) + } else { + None + } + } + + /// Creates a new binary formatted integer value. + /// Returns `None` if the `value` is negative. + pub fn new_bin(value: i64) -> Option { + if value >= 0 { + Some(Self { + value, + repr: Some(Repr::new_unchecked(format!("{:#b}", value))), + decor: Default::default(), + }) + } else { + None + } + } +} + impl std::fmt::Debug for Formatted where T: std::fmt::Debug, diff --git a/crates/toml_edit/tests/testsuite/edit.rs b/crates/toml_edit/tests/testsuite/edit.rs index 84c53d05c..81f7d30a1 100644 --- a/crates/toml_edit/tests/testsuite/edit.rs +++ b/crates/toml_edit/tests/testsuite/edit.rs @@ -3,7 +3,7 @@ use std::iter::FromIterator; use snapbox::assert_data_eq; use snapbox::prelude::*; use snapbox::str; -use toml_edit::{array, table, value, DocumentMut, Item, Key, Table, Value}; +use toml_edit::{array, table, value, DocumentMut, Formatted, Item, Key, Table, Value}; macro_rules! parse_key { ($s:expr) => {{ @@ -1026,3 +1026,32 @@ name = "test.swf" "#]] ); } + +#[test] +fn integer_bases() { + given(r#"[table]"#) + .running(|root| { + let table = root.get_mut("table").unwrap().as_table_mut().unwrap(); + + table["hex_upper"] = Value::Integer(Formatted::new_hex_upper(42).unwrap()).into(); + table["hex_lower"] = Value::Integer(Formatted::new_hex_lower(42).unwrap()).into(); + table["octal"] = Value::Integer(Formatted::new_oct(42).unwrap()).into(); + table["binary"] = Value::Integer(Formatted::new_bin(42).unwrap()).into(); + }) + .produces_display(str![[r#" +[table] +hex_upper = 0x2A +hex_lower = 0x2a +octal = 0o52 +binary = 0b101010 + +"#]]); +} + +#[test] +fn integer_bases_reject_negative() { + assert_eq!(Formatted::new_hex_upper(-42), None); + assert_eq!(Formatted::new_hex_lower(-42), None); + assert_eq!(Formatted::new_oct(-42), None); + assert_eq!(Formatted::new_bin(-42), None); +}