use ordered_float::OrderedFloat; use rug::*; use std::collections::BTreeMap; use crate::atom_table::*; #[derive(Debug, Clone, PartialEq, Eq)] pub enum QueryResult { True, False, Matches(Vec), } #[derive(Debug, Clone, PartialEq, Eq)] pub enum QueryResultLine { True, False, Match(BTreeMap), } #[derive(Debug, Clone, PartialEq, Eq)] pub enum Value { Integer(Integer), Rational(Rational), Float(OrderedFloat), Atom(Atom), String(String), List(Vec), Structure(Atom, Vec), Var, } impl From> for QueryResult { fn from(query_result_lines: Vec) -> Self { // If there is only one line, and it is true or false, return that. if query_result_lines.len() == 1 { match query_result_lines[0].clone() { QueryResultLine::True => return QueryResult::True, QueryResultLine::False => return QueryResult::False, _ => {} } } // If there is at least one line with true and no matches, return true. if query_result_lines.iter().any(|l| l == &QueryResultLine::True) && !query_result_lines.iter().any(|l| { if let &QueryResultLine::Match(_) = l { true } else { false } }) { return QueryResult::True; } // If there is at least one match, return all matches. if query_result_lines.iter().any(|l| { if let &QueryResultLine::Match(_) = l { true } else { false } }) { let all_matches = query_result_lines.into_iter() .filter(|l| { if let &QueryResultLine::Match(_) = l { true } else { false } }) .collect::>(); return QueryResult::Matches(all_matches); } QueryResult::False } } impl TryFrom for QueryResultLine { type Error = (); fn try_from(string: String) -> Result { match string.as_str() { "true" => Ok(QueryResultLine::True), "false" => Ok(QueryResultLine::False), _ => Ok(QueryResultLine::Match( string.split(",") .map(|s| s.trim()) .filter(|s| !s.is_empty()) .map(|s| -> Result<(String, Value), ()>{ let mut iter = s.split(" = "); let key = iter.next().unwrap().to_string(); let value = iter.next().unwrap().to_string(); Ok((key, Value::try_from(value)?)) }) .filter_map(Result::ok) .collect::>() )) } } } impl TryFrom for Value { type Error = (); fn try_from(string: String) -> Result { let trimmed = string.trim(); if trimmed.starts_with("'") && trimmed.ends_with("'") { Ok(Value::String(trimmed[1..trimmed.len() - 1].into())) } else if trimmed.starts_with("\"") && trimmed.ends_with("\"") { Ok(Value::String(trimmed[1..trimmed.len() - 1].into())) } else if trimmed.starts_with("[") && trimmed.ends_with("]") { let mut iter = trimmed[1..trimmed.len() - 1].split(","); let mut values = vec![]; while let Some(s) = iter.next() { values.push(Value::try_from(s.to_string())?); } Ok(Value::List(values)) } else if trimmed.starts_with("{") && trimmed.ends_with("}") { let mut iter = trimmed[1..trimmed.len() - 1].split(","); let mut values = vec![]; while let Some(value) = iter.next() { let mut iter = value.split(":"); let _key = iter.next().unwrap().to_string(); let value = iter.next().unwrap().to_string(); values.push(Value::try_from(value)?); } Ok(Value::Structure(atom!("{}"), values)) } else if trimmed.starts_with("<<") && trimmed.ends_with(">>") { let mut iter = trimmed[2..trimmed.len() - 2].split(","); let mut values = vec![]; while let Some(value) = iter.next() { let mut iter = value.split(":"); let _key = iter.next().unwrap().to_string(); let value = iter.next().unwrap().to_string(); values.push(Value::try_from(value)?); } Ok(Value::Structure(atom!("<<>>"), values)) } else { Err(()) } } }