-4

I want to write a function in Rust that can parse a JSON string and output a modified JSON with all the number fields converted to string. All other fields should be unchanged. Structure of the JSON string is not known in advance. Here's the desired function signature:

pub fn convert_all_numbers_to_string(json: &str) -> String

Examples:

Input:
{"foo": 18446744073709551615}

Output:
{"foo": "18446744073709551615"}
Input:
{
    "some": [{
        "deeply": {
            "nested": [{
                "path": 123
            }]
        }
    }]
}

Output:
{
    "some": [{
        "deeply": {
            "nested": [{
                "path": "123"
            }]
        }
    }]
}
Herohtar
  • 5,347
  • 4
  • 31
  • 41
onyb
  • 68
  • 2
  • 4
  • JSON doesn't have a way to determine integer sizes, do you maybe mean "all integers" instead of "all u64"? – Finomnis Aug 10 '22 at 13:46
  • I was actually hoping to stringify only for values where `.is_u64()` is true. An example snippet for "all integers" works for me too. – onyb Aug 10 '22 at 13:50
  • `String` does not have a `.is_u64()` function. What function are you talking about? – Finomnis Aug 10 '22 at 13:51
  • For context: JSON itself does not have the concept of a `u64`, but `serde_json` has a generic [`Number`](https://docs.rs/serde_json/latest/serde_json/struct.Number.html) type which enables users to check whether the number would fit in a Rust `u64`. This still does not clarify what the problem is. Where did you get stuck? – E_net4 Aug 10 '22 at 13:56
  • Sorry, I forgot to add that `.is_u64()` call is on `serde_json::Value`. It's not an important detail, so I'll go ahead and update the question to be about converting all number fields to strings. – onyb Aug 10 '22 at 13:59
  • @onyb All "numbers" or all "integers"? "floats" are also numbers ... I think you need to work on your specification game ;) – Finomnis Aug 10 '22 at 14:01
  • 1
    But I agree with @E_net4thecommentflagger; SO is not meant to be a coding request website, so please show us your attempt so we can assist you :) – Finomnis Aug 10 '22 at 14:03

1 Answers1

2

Here you go:

pub fn convert_all_ints_to_strings(json: &str) -> Result<String, serde_json::Error> {
    use serde_json::Value;

    fn convert_recursively(json: &mut Value) {
        match json {
            Value::Number(n) if n.is_u64() || n.is_i64() => {
                *json = Value::String(n.to_string());
            }
            Value::Array(a) => a.iter_mut().for_each(convert_recursively),
            Value::Object(o) => o.values_mut().for_each(convert_recursively),
            _ => (),
        }
    }

    serde_json::from_str(json).map(|mut v: Value| {
        convert_recursively(&mut v);
        v.to_string()
    })
}

Used in a main():

fn main() {
    let inp = r#"
        {
            "some": [{
                "deeply": {
                    "nested": [{
                        "path": 123
                    }]
                }
            }]
        }
    "#;

    let outp = convert_all_ints_to_strings(inp).unwrap();

    println!("{}", outp);
}
{"some":[{"deeply":{"nested":[{"path":"123"}]}}]}
Finomnis
  • 18,094
  • 1
  • 20
  • 27