1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
/* in fact this function is sequence of calls to `parse_single_key_value` /// parse_key_value parses response in following format: /// ```text /// KEYWORD1=VALUE1 /// KEYWORD2=VALUE2 /// ... /// ``` /// where keywords are A-Z ascii letters and value is either quoted string or just string. pub fn parse_key_value() {} */ /// parse_single_key_value parses response in following format: /// ```text /// KEYWORD=VALUE /// ... /// ``` /// /// # Params /// if `must_be_quoted` flag is set an error will be returned when string after equal sign is not quoted string /// /// # Error /// It returns an error: /// - if there is no equal sign /// - if data before equal sign is not `A-Za-z0-9_ -/` ascii chars(notice space character) /// - if value as quoted string enclosing quote is not last character of text /// /// It *does not* return an error when key value is empty string so format is: `="asdf"` /// /// # Example /// ``` /// use torut::utils::parse_single_key_value; /// assert_eq!(parse_single_key_value("KEY=VALUE"), Ok(("KEY", "VALUE"))); /// assert_eq!(parse_single_key_value("INVALID"), Err(())); /// assert_eq!(parse_single_key_value("VALID="), Ok(("VALID", ""))); /// assert_eq!(parse_single_key_value("KEY=\"QUOTED VALUE\""), Ok(("KEY", "\"QUOTED VALUE\""))); /// ``` pub fn parse_single_key_value(text: &str) -> Result<(&str, &str), ()> { assert!(text.len() <= std::usize::MAX - 1, "too long string provided to `parse_single_key_value`"); // notice this `+ 1` next to key offset let mut key_offset = 0; for c in text.chars() { if c == '=' { break; } if c != ' ' && c != '-' && c != '_' && c != '/' && !c.is_ascii_alphanumeric() { return Err(()); } key_offset += c.len_utf8(); } if key_offset >= text.len() { return Err(()); // there is no equal sign } let key = &text[..key_offset]; let value = &text[key_offset + 1..]; /* let (offset, res) = unquote_string(&text[key_offset + 1..]); if must_be_quoted && offset.is_none() { return Err(()); } if let Some(offset) = offset { if key_offset + 1 + offset != text.len() - 1 { return Err(()); // end quote is not last char of input text } }*/ Ok((key, value)) } #[cfg(test)] mod test { use super::*; #[test] fn test_can_parse_single_key_value() { for (i, o) in [ ( "KEY=VALUE", Some(("KEY", "VALUE")) ), ( "KEY=\"VALUE\"", Some(("KEY", "\"VALUE\"")) ), ( "KEY=Some\nMultiline\nValue\nIt\nHappens\nSometimes", Some(("KEY", "Some\nMultiline\nValue\nIt\nHappens\nSometimes")), ) ].iter().cloned() { if let Some(o) = o { let (k, v) = o; let (key, res) = parse_single_key_value(i).unwrap(); assert_eq!(key, k); assert_eq!(res, v); } else { let _ = parse_single_key_value(i).unwrap_err(); } } } }