use crate::ported::lint::markedjson::nodes::Mark;
use serde_json::{Map, Value};
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MarkedUnicode {
pub value: String,
pub mark: Mark,
}
impl MarkedUnicode {
pub fn new(value: impl Into<String>, mark: Mark) -> Self {
Self {
value: value.into(),
mark,
}
}
fn _proc_partition(&self, parts: [&str; 3]) -> (MarkedUnicode, MarkedUnicode, MarkedUnicode) {
let mut pointdiff: usize = 1;
let mut out = Vec::with_capacity(3);
for s in parts {
out.push(MarkedUnicode::new(s.to_string(), self.mark.clone()));
pointdiff += s.len();
}
let _ = pointdiff;
(out.remove(0), out.remove(0), out.remove(0))
}
pub fn rpartition(&self, sep: &str) -> (MarkedUnicode, MarkedUnicode, MarkedUnicode) {
let parts = match self.value.rfind(sep) {
Some(i) => {
let (pre, after) = self.value.split_at(i);
let post = &after[sep.len()..];
[pre, sep, post]
}
None => ["", "", self.value.as_str()],
};
self._proc_partition(parts)
}
pub fn partition(&self, sep: &str) -> (MarkedUnicode, MarkedUnicode, MarkedUnicode) {
let parts = match self.value.find(sep) {
Some(i) => {
let (pre, after) = self.value.split_at(i);
let post = &after[sep.len()..];
[pre, sep, post]
}
None => [self.value.as_str(), "", ""],
};
self._proc_partition(parts)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MarkedInt {
pub value: i64,
pub mark: Mark,
}
impl MarkedInt {
pub fn new(value: i64, mark: Mark) -> Self {
Self { value, mark }
}
}
#[derive(Debug, Clone)]
pub struct MarkedFloat {
pub value: f64,
pub mark: Mark,
}
impl MarkedFloat {
pub fn new(value: f64, mark: Mark) -> Self {
Self { value, mark }
}
}
#[derive(Debug, Clone)]
pub struct MarkedDict {
pub value: Map<String, Value>,
pub mark: Mark,
pub keydict: HashMap<String, MarkedUnicode>,
}
impl MarkedDict {
pub fn new(value: Map<String, Value>, mark: Mark) -> Self {
let keydict = value
.keys()
.map(|k| (k.clone(), MarkedUnicode::new(k.clone(), mark.clone())))
.collect();
Self {
value,
mark,
keydict,
}
}
pub fn setmerged(&self, _other_mark: Mark) {
}
pub fn update(&mut self, other: Map<String, Value>) {
for (k, v) in other {
self.value.insert(k.clone(), v);
self.keydict
.insert(k.clone(), MarkedUnicode::new(k, self.mark.clone()));
}
}
pub fn copy(&self) -> MarkedDict {
MarkedDict::new(self.value.clone(), self.mark.clone())
}
}
#[derive(Debug, Clone)]
pub struct MarkedList {
pub value: Vec<Value>,
pub mark: Mark,
}
impl MarkedList {
pub fn new(value: Vec<Value>, mark: Mark) -> Self {
Self { value, mark }
}
}
#[derive(Debug, Clone)]
pub struct MarkedValue {
pub value: Value,
pub mark: Mark,
}
impl MarkedValue {
pub fn new(value: Value, mark: Mark) -> Self {
Self { value, mark }
}
}
#[derive(Debug, Clone)]
pub enum MarkedAny {
Unicode(MarkedUnicode),
Int(MarkedInt),
Float(MarkedFloat),
Dict(MarkedDict),
List(MarkedList),
Other(MarkedValue),
}
pub fn gen_new<V>(value: V, mark: Mark) -> (V, Mark) {
(value, mark)
}
pub fn gen_init<V>(value: V) -> V {
value
}
pub fn gen_getnewargs<V>(value: V, mark: Mark) -> (V, Mark) {
(value, mark)
}
pub fn gen_marked_value(value: Value, mark: Mark) -> MarkedAny {
match value {
Value::String(s) => MarkedAny::Unicode(MarkedUnicode::new(s, mark)),
Value::Number(n) => {
if let Some(i) = n.as_i64() {
MarkedAny::Int(MarkedInt::new(i, mark))
} else if let Some(f) = n.as_f64() {
MarkedAny::Float(MarkedFloat::new(f, mark))
} else {
MarkedAny::Other(MarkedValue::new(Value::Number(n), mark))
}
}
Value::Object(m) => MarkedAny::Dict(MarkedDict::new(m, mark)),
Value::Array(a) => MarkedAny::List(MarkedList::new(a, mark)),
other => MarkedAny::Other(MarkedValue::new(other, mark)),
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
fn mk() -> Mark {
Mark { line: 1, column: 0 }
}
#[test]
fn marked_unicode_carries_value_and_mark() {
let m = MarkedUnicode::new("hello", mk());
assert_eq!(m.value, "hello");
assert_eq!(m.mark, mk());
}
#[test]
fn marked_unicode_partition_returns_three_parts() {
let m = MarkedUnicode::new("a.b.c", mk());
let (pre, sep, post) = m.partition(".");
assert_eq!(pre.value, "a");
assert_eq!(sep.value, ".");
assert_eq!(post.value, "b.c");
}
#[test]
fn marked_unicode_rpartition_returns_three_parts() {
let m = MarkedUnicode::new("a.b.c", mk());
let (pre, sep, post) = m.rpartition(".");
assert_eq!(pre.value, "a.b");
assert_eq!(sep.value, ".");
assert_eq!(post.value, "c");
}
#[test]
fn marked_unicode_partition_no_sep_returns_first_in_pre() {
let m = MarkedUnicode::new("abc", mk());
let (pre, sep, post) = m.partition(".");
assert_eq!(pre.value, "abc");
assert_eq!(sep.value, "");
assert_eq!(post.value, "");
}
#[test]
fn marked_dict_carries_keydict_for_every_key() {
let mut value = Map::new();
value.insert("a".into(), json!(1));
value.insert("b".into(), json!(2));
let d = MarkedDict::new(value, mk());
assert_eq!(d.keydict.len(), 2);
assert_eq!(d.keydict["a"].value, "a");
assert_eq!(d.keydict["b"].value, "b");
}
#[test]
fn marked_dict_copy_clones_value_and_keydict() {
let mut value = Map::new();
value.insert("a".into(), json!(1));
let d = MarkedDict::new(value, mk());
let d2 = d.copy();
assert_eq!(d2.value.len(), 1);
assert!(d2.keydict.contains_key("a"));
}
#[test]
fn marked_dict_update_adds_to_keydict() {
let value = Map::new();
let mut d = MarkedDict::new(value, mk());
let mut more = Map::new();
more.insert("x".into(), json!(99));
d.update(more);
assert!(d.keydict.contains_key("x"));
}
#[test]
fn gen_marked_value_dispatches_on_value_type() {
assert!(matches!(
gen_marked_value(json!("s"), mk()),
MarkedAny::Unicode(_)
));
assert!(matches!(
gen_marked_value(json!(42), mk()),
MarkedAny::Int(_)
));
assert!(matches!(
gen_marked_value(json!(2.5_f64), mk()),
MarkedAny::Float(_)
));
assert!(matches!(
gen_marked_value(json!({"a": 1}), mk()),
MarkedAny::Dict(_)
));
assert!(matches!(
gen_marked_value(json!([1, 2]), mk()),
MarkedAny::List(_)
));
assert!(matches!(
gen_marked_value(Value::Null, mk()),
MarkedAny::Other(_)
));
}
#[test]
fn marked_int_carries_i64() {
let m = MarkedInt::new(42, mk());
assert_eq!(m.value, 42);
}
#[test]
fn marked_float_carries_f64() {
let m = MarkedFloat::new(2.5, mk());
assert!((m.value - 2.5).abs() < 1e-9);
}
#[test]
fn gen_new_returns_value_mark_pair() {
let (v, m) = gen_new("hello".to_string(), mk());
assert_eq!(v, "hello");
assert_eq!(m.line, 1);
}
#[test]
fn gen_init_passes_value_through() {
assert_eq!(gen_init(42), 42);
assert_eq!(gen_init("str".to_string()), "str");
}
#[test]
fn gen_getnewargs_returns_value_mark_pair() {
let (v, m) = gen_getnewargs(7.5, mk());
assert_eq!(v, 7.5);
assert_eq!(m.column, 0);
}
}