add_one/
lib.rs

1//! This add-one crate is meant to give you the opportunity to add one to a number.
2//! 
3//! # Examples
4//! 
5//! ```
6//!extern crate add_one;
7//!use add_one::add_one;
8//!
9//!use std::str;
10//!
11//!fn main() {
12//!    let mut bytes = Vec::new();
13//!
14//!    match add_one("123".as_bytes(), &mut bytes) {
15//!        Ok(()) => println!("{}", str::from_utf8(&bytes).unwrap()),
16//!        Err(e) => {
17//!            eprintln!("Error: {}", e);
18//!        }
19//!    }
20//!}
21//! ```
22//!
23//! ## Compatibility
24//!
25//! The `add-one` crate is tested for rustc 1.26 and greater.
26
27use std::io;
28
29pub fn add_one<T: io::Write>(digits: &[u8], output: &mut T) -> Result<(), io::Error> {
30    // Parse the leading '-' for negative numbers.
31    let (minus, digits) = match digits.split_first() {
32        Some((&b'-', digits)) => (true, digits), // Negative number
33        _ => (false, digits),
34    };
35
36    // Validate (ASCII) digits.
37    if digits.is_empty() || !digits.iter().all(|&c| c >= b'0' && c <= b'9' || c == b'.') {
38        return Err(io::Error::new(
39            io::ErrorKind::InvalidInput,
40            "Invalid characters in input".to_string(),
41        ));
42    }
43
44    // Remove any leading zeros.
45    let digits = &digits[digits.iter().position(|&c| c != b'0').unwrap_or(digits.len())..];
46
47    let z = digits.iter().position(|&c| c == b'.').unwrap_or(digits.len()); // position of decimal
48
49    // Find any trailing 9's (when positive) or 0's (when negative) which will carry the carry bit.
50    let (prefix, trailing) = digits[..z].split_at(
51        digits[..z].iter()
52            .rposition(|&c| c != if minus { b'0' } else { b'9' })
53            .map_or(0, |x| x + 1) // The position *after* the last non-nine/zero.
54    );
55
56    if let Some((&digit, prefix)) = prefix.split_last() {
57        // The last digit before that will have to be incremented/decremented,
58        // and anything before it is left unchanged.
59        let new_digit = if minus {
60            if prefix.is_empty() && trailing.is_empty() && digit == b'1' {
61                // Special case for -1: Result is no longer negative.
62                return output.write_all(b"0");
63            }
64            output.write_all(b"-")?;
65            digit - 1
66        } else {
67            digit + 1
68        };
69        // Write prefix, unchanged.
70        output.write_all(prefix)?;
71        // Write changed digit, unless it became a leading zero.
72        if !prefix.is_empty() || new_digit != b'0' {
73            output.write_all(&[new_digit])?;
74        }
75    } else if minus && digits.len() > 0 && digits[0] == b'.' && !digits[1..].iter().all(|&d| d == b'0') {
76        output.write_all(b"0")?;
77    } else {
78        output.write_all(b"1")?;
79    }
80    for _ in 0..trailing.len() {
81        output.write_all(if minus { b"9" } else { b"0" })?;
82    }
83    if minus && z == 0 && digits.len() > 1 {
84        // write decimal
85        output.write_all(&digits[0..1])?;
86        let mut iter = digits[1..].iter().rev().peekable();
87        let mut decimal_digits = Vec::new();
88        while let Some(&b'0') = iter.peek() {
89            decimal_digits.push(*iter.next().unwrap());
90        }
91        if let Some(_) = iter.peek() {
92            decimal_digits.push(b'9' - *iter.next().unwrap() + b'0' + 1);
93        }
94        while let Some(_) = iter.peek() {
95            decimal_digits.push(b'9' - *iter.next().unwrap() + b'0');
96        }
97        output.write_all(decimal_digits.iter().rev().cloned().collect::<Vec<u8>>().as_slice())?;
98    } else {
99        output.write_all(&digits[z..])?;// prints the characters after decimal
100    }
101    Ok(())
102}
103
104#[test]
105fn add_one_test_integer() {
106    fn test(num: &str, result: &str) {
107        use std::str::from_utf8;
108        let mut s = Vec::new();
109        add_one(num.as_bytes(), &mut s).unwrap();
110        assert_eq!(from_utf8(&s).unwrap(), result);
111    }
112    test("1234", "1235");
113    test("0", "1");
114    test("9", "10");
115    test("19", "20");
116    test("99", "100");
117    test("99988999", "99989000");
118    test("99999999", "100000000");
119    test("0001234", "1235");
120    test("-9", "-8");
121    test("-10", "-9");
122    test("-100", "-99");
123    test("-0100", "-99");
124    test("-1100", "-1099");
125    test("-01100", "-1099");
126    test("-1", "0");
127    test("-001", "0");
128    test("-0", "1");
129    test("-000", "1");
130    test(
131        "1256146513513224524524524524522452165841613615616516516",
132        "1256146513513224524524524524522452165841613615616516517",
133    );
134    test(
135        "1237801293471034709342345050491203491230949139249123949999999",
136        "1237801293471034709342345050491203491230949139249123950000000",
137    );
138    test(
139        "-1237801293471034709342345050491203491230949139249123940000000",
140        "-1237801293471034709342345050491203491230949139249123939999999",
141    );
142    test("-2", "-1");
143}
144
145#[test]
146fn add_one_test_float() {
147    fn test(num: &str, result: &str) {
148        use std::str::from_utf8;
149        let mut s = Vec::new();
150        add_one(num.as_bytes(), &mut s).unwrap();
151        assert_eq!(from_utf8(&s).unwrap(), result);
152    }
153    test("0.0", "1.0");
154    test("5000.0", "5001.0");
155    test("1139.67", "1140.67");
156    test("123.321", "124.321");
157    test("99.99", "100.99");
158    test("-1.0", "0");
159    test("2.0", "3.0");
160    test("000.000", "1.000");
161    test("-000.00", "1.00");
162    test("-0.9", "0.1");
163    test("-0.76987965465", "0.23012034535");
164    test("0123456789.0987654321", "123456790.0987654321");
165}
166