16855e09eSopenharmony_ciuse nom::{ 26855e09eSopenharmony_ci bytes::complete::{is_a, tag, take_till, take_while}, 36855e09eSopenharmony_ci character::complete::{alphanumeric1 as alphanumeric, char, space0 as space}, 46855e09eSopenharmony_ci combinator::opt, 56855e09eSopenharmony_ci multi::many0, 66855e09eSopenharmony_ci sequence::{delimited, pair, terminated, tuple}, 76855e09eSopenharmony_ci IResult, 86855e09eSopenharmony_ci}; 96855e09eSopenharmony_ci 106855e09eSopenharmony_ciuse std::collections::HashMap; 116855e09eSopenharmony_ci 126855e09eSopenharmony_cifn is_line_ending_or_comment(chr: char) -> bool { 136855e09eSopenharmony_ci chr == ';' || chr == '\n' 146855e09eSopenharmony_ci} 156855e09eSopenharmony_ci 166855e09eSopenharmony_cifn not_line_ending(i: &str) -> IResult<&str, &str> { 176855e09eSopenharmony_ci take_while(|c| c != '\r' && c != '\n')(i) 186855e09eSopenharmony_ci} 196855e09eSopenharmony_ci 206855e09eSopenharmony_cifn space_or_line_ending(i: &str) -> IResult<&str, &str> { 216855e09eSopenharmony_ci is_a(" \r\n")(i) 226855e09eSopenharmony_ci} 236855e09eSopenharmony_ci 246855e09eSopenharmony_cifn category(i: &str) -> IResult<&str, &str> { 256855e09eSopenharmony_ci terminated( 266855e09eSopenharmony_ci delimited(char('['), take_while(|c| c != ']'), char(']')), 276855e09eSopenharmony_ci opt(is_a(" \r\n")), 286855e09eSopenharmony_ci )(i) 296855e09eSopenharmony_ci} 306855e09eSopenharmony_ci 316855e09eSopenharmony_cifn key_value(i: &str) -> IResult<&str, (&str, &str)> { 326855e09eSopenharmony_ci let (i, key) = alphanumeric(i)?; 336855e09eSopenharmony_ci let (i, _) = tuple((opt(space), tag("="), opt(space)))(i)?; 346855e09eSopenharmony_ci let (i, val) = take_till(is_line_ending_or_comment)(i)?; 356855e09eSopenharmony_ci let (i, _) = opt(space)(i)?; 366855e09eSopenharmony_ci let (i, _) = opt(pair(tag(";"), not_line_ending))(i)?; 376855e09eSopenharmony_ci let (i, _) = opt(space_or_line_ending)(i)?; 386855e09eSopenharmony_ci 396855e09eSopenharmony_ci Ok((i, (key, val))) 406855e09eSopenharmony_ci} 416855e09eSopenharmony_ci 426855e09eSopenharmony_cifn keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>> { 436855e09eSopenharmony_ci many0(key_value)(i) 446855e09eSopenharmony_ci} 456855e09eSopenharmony_ci 466855e09eSopenharmony_cifn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> { 476855e09eSopenharmony_ci match keys_and_values_aggregator(input) { 486855e09eSopenharmony_ci Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())), 496855e09eSopenharmony_ci Err(e) => Err(e), 506855e09eSopenharmony_ci } 516855e09eSopenharmony_ci} 526855e09eSopenharmony_ci 536855e09eSopenharmony_cifn category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)> { 546855e09eSopenharmony_ci pair(category, keys_and_values)(i) 556855e09eSopenharmony_ci} 566855e09eSopenharmony_ci 576855e09eSopenharmony_cifn categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>> { 586855e09eSopenharmony_ci many0(category_and_keys)(i) 596855e09eSopenharmony_ci} 606855e09eSopenharmony_ci 616855e09eSopenharmony_cifn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> { 626855e09eSopenharmony_ci match categories_aggregator(input) { 636855e09eSopenharmony_ci Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())), 646855e09eSopenharmony_ci Err(e) => Err(e), 656855e09eSopenharmony_ci } 666855e09eSopenharmony_ci} 676855e09eSopenharmony_ci 686855e09eSopenharmony_ci#[test] 696855e09eSopenharmony_cifn parse_category_test() { 706855e09eSopenharmony_ci let ini_file = "[category] 716855e09eSopenharmony_ci 726855e09eSopenharmony_ciparameter=value 736855e09eSopenharmony_cikey = value2"; 746855e09eSopenharmony_ci 756855e09eSopenharmony_ci let ini_without_category = "parameter=value 766855e09eSopenharmony_cikey = value2"; 776855e09eSopenharmony_ci 786855e09eSopenharmony_ci let res = category(ini_file); 796855e09eSopenharmony_ci println!("{:?}", res); 806855e09eSopenharmony_ci match res { 816855e09eSopenharmony_ci Ok((i, o)) => println!("i: {} | o: {:?}", i, o), 826855e09eSopenharmony_ci _ => println!("error"), 836855e09eSopenharmony_ci } 846855e09eSopenharmony_ci 856855e09eSopenharmony_ci assert_eq!(res, Ok((ini_without_category, "category"))); 866855e09eSopenharmony_ci} 876855e09eSopenharmony_ci 886855e09eSopenharmony_ci#[test] 896855e09eSopenharmony_cifn parse_key_value_test() { 906855e09eSopenharmony_ci let ini_file = "parameter=value 916855e09eSopenharmony_cikey = value2"; 926855e09eSopenharmony_ci 936855e09eSopenharmony_ci let ini_without_key_value = "key = value2"; 946855e09eSopenharmony_ci 956855e09eSopenharmony_ci let res = key_value(ini_file); 966855e09eSopenharmony_ci println!("{:?}", res); 976855e09eSopenharmony_ci match res { 986855e09eSopenharmony_ci Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), 996855e09eSopenharmony_ci _ => println!("error"), 1006855e09eSopenharmony_ci } 1016855e09eSopenharmony_ci 1026855e09eSopenharmony_ci assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); 1036855e09eSopenharmony_ci} 1046855e09eSopenharmony_ci 1056855e09eSopenharmony_ci#[test] 1066855e09eSopenharmony_cifn parse_key_value_with_space_test() { 1076855e09eSopenharmony_ci let ini_file = "parameter = value 1086855e09eSopenharmony_cikey = value2"; 1096855e09eSopenharmony_ci 1106855e09eSopenharmony_ci let ini_without_key_value = "key = value2"; 1116855e09eSopenharmony_ci 1126855e09eSopenharmony_ci let res = key_value(ini_file); 1136855e09eSopenharmony_ci println!("{:?}", res); 1146855e09eSopenharmony_ci match res { 1156855e09eSopenharmony_ci Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), 1166855e09eSopenharmony_ci _ => println!("error"), 1176855e09eSopenharmony_ci } 1186855e09eSopenharmony_ci 1196855e09eSopenharmony_ci assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); 1206855e09eSopenharmony_ci} 1216855e09eSopenharmony_ci 1226855e09eSopenharmony_ci#[test] 1236855e09eSopenharmony_cifn parse_key_value_with_comment_test() { 1246855e09eSopenharmony_ci let ini_file = "parameter=value;abc 1256855e09eSopenharmony_cikey = value2"; 1266855e09eSopenharmony_ci 1276855e09eSopenharmony_ci let ini_without_key_value = "key = value2"; 1286855e09eSopenharmony_ci 1296855e09eSopenharmony_ci let res = key_value(ini_file); 1306855e09eSopenharmony_ci println!("{:?}", res); 1316855e09eSopenharmony_ci match res { 1326855e09eSopenharmony_ci Ok((i, (o1, o2))) => println!("i: {} | o: ({:?},{:?})", i, o1, o2), 1336855e09eSopenharmony_ci _ => println!("error"), 1346855e09eSopenharmony_ci } 1356855e09eSopenharmony_ci 1366855e09eSopenharmony_ci assert_eq!(res, Ok((ini_without_key_value, ("parameter", "value")))); 1376855e09eSopenharmony_ci} 1386855e09eSopenharmony_ci 1396855e09eSopenharmony_ci#[test] 1406855e09eSopenharmony_cifn parse_multiple_keys_and_values_test() { 1416855e09eSopenharmony_ci let ini_file = "parameter=value;abc 1426855e09eSopenharmony_ci 1436855e09eSopenharmony_cikey = value2 1446855e09eSopenharmony_ci 1456855e09eSopenharmony_ci[category]"; 1466855e09eSopenharmony_ci 1476855e09eSopenharmony_ci let ini_without_key_value = "[category]"; 1486855e09eSopenharmony_ci 1496855e09eSopenharmony_ci let res = keys_and_values(ini_file); 1506855e09eSopenharmony_ci println!("{:?}", res); 1516855e09eSopenharmony_ci match res { 1526855e09eSopenharmony_ci Ok((i, ref o)) => println!("i: {} | o: {:?}", i, o), 1536855e09eSopenharmony_ci _ => println!("error"), 1546855e09eSopenharmony_ci } 1556855e09eSopenharmony_ci 1566855e09eSopenharmony_ci let mut expected: HashMap<&str, &str> = HashMap::new(); 1576855e09eSopenharmony_ci expected.insert("parameter", "value"); 1586855e09eSopenharmony_ci expected.insert("key", "value2"); 1596855e09eSopenharmony_ci assert_eq!(res, Ok((ini_without_key_value, expected))); 1606855e09eSopenharmony_ci} 1616855e09eSopenharmony_ci 1626855e09eSopenharmony_ci#[test] 1636855e09eSopenharmony_cifn parse_category_then_multiple_keys_and_values_test() { 1646855e09eSopenharmony_ci //FIXME: there can be an empty line or a comment line after a category 1656855e09eSopenharmony_ci let ini_file = "[abcd] 1666855e09eSopenharmony_ciparameter=value;abc 1676855e09eSopenharmony_ci 1686855e09eSopenharmony_cikey = value2 1696855e09eSopenharmony_ci 1706855e09eSopenharmony_ci[category]"; 1716855e09eSopenharmony_ci 1726855e09eSopenharmony_ci let ini_after_parser = "[category]"; 1736855e09eSopenharmony_ci 1746855e09eSopenharmony_ci let res = category_and_keys(ini_file); 1756855e09eSopenharmony_ci println!("{:?}", res); 1766855e09eSopenharmony_ci match res { 1776855e09eSopenharmony_ci Ok((i, ref o)) => println!("i: {} | o: {:?}", i, o), 1786855e09eSopenharmony_ci _ => println!("error"), 1796855e09eSopenharmony_ci } 1806855e09eSopenharmony_ci 1816855e09eSopenharmony_ci let mut expected_h: HashMap<&str, &str> = HashMap::new(); 1826855e09eSopenharmony_ci expected_h.insert("parameter", "value"); 1836855e09eSopenharmony_ci expected_h.insert("key", "value2"); 1846855e09eSopenharmony_ci assert_eq!(res, Ok((ini_after_parser, ("abcd", expected_h)))); 1856855e09eSopenharmony_ci} 1866855e09eSopenharmony_ci 1876855e09eSopenharmony_ci#[test] 1886855e09eSopenharmony_cifn parse_multiple_categories_test() { 1896855e09eSopenharmony_ci let ini_file = "[abcd] 1906855e09eSopenharmony_ci 1916855e09eSopenharmony_ciparameter=value;abc 1926855e09eSopenharmony_ci 1936855e09eSopenharmony_cikey = value2 1946855e09eSopenharmony_ci 1956855e09eSopenharmony_ci[category] 1966855e09eSopenharmony_ciparameter3=value3 1976855e09eSopenharmony_cikey4 = value4 1986855e09eSopenharmony_ci"; 1996855e09eSopenharmony_ci 2006855e09eSopenharmony_ci let res = categories(ini_file); 2016855e09eSopenharmony_ci //println!("{:?}", res); 2026855e09eSopenharmony_ci match res { 2036855e09eSopenharmony_ci Ok((i, ref o)) => println!("i: {} | o: {:?}", i, o), 2046855e09eSopenharmony_ci _ => println!("error"), 2056855e09eSopenharmony_ci } 2066855e09eSopenharmony_ci 2076855e09eSopenharmony_ci let mut expected_1: HashMap<&str, &str> = HashMap::new(); 2086855e09eSopenharmony_ci expected_1.insert("parameter", "value"); 2096855e09eSopenharmony_ci expected_1.insert("key", "value2"); 2106855e09eSopenharmony_ci let mut expected_2: HashMap<&str, &str> = HashMap::new(); 2116855e09eSopenharmony_ci expected_2.insert("parameter3", "value3"); 2126855e09eSopenharmony_ci expected_2.insert("key4", "value4"); 2136855e09eSopenharmony_ci let mut expected_h: HashMap<&str, HashMap<&str, &str>> = HashMap::new(); 2146855e09eSopenharmony_ci expected_h.insert("abcd", expected_1); 2156855e09eSopenharmony_ci expected_h.insert("category", expected_2); 2166855e09eSopenharmony_ci assert_eq!(res, Ok(("", expected_h))); 2176855e09eSopenharmony_ci} 218