mark encode/decode/serde
This commit is contained in:
parent
b794f4803d
commit
a2e433348a
12 changed files with 203 additions and 149 deletions
|
@ -3,7 +3,7 @@ const assert = require('assert')
|
|||
const util = require('util')
|
||||
const { BloomFilter } = require('./helpers/sync')
|
||||
const Automerge = require('..')
|
||||
const { MAP, LIST, TEXT, initSyncState, decodeSyncMessage, decodeSyncState, encodeSyncState }= Automerge
|
||||
const { MAP, LIST, TEXT, encodeChange, decodeChange, initSyncState, decodeSyncMessage, decodeSyncState, encodeSyncState }= Automerge
|
||||
|
||||
// str to uint8array
|
||||
function en(str) {
|
||||
|
@ -460,6 +460,15 @@ describe('Automerge', () => {
|
|||
doc.insert(list, 2, "A")
|
||||
spans = doc.spans(list);
|
||||
assert.deepStrictEqual(spans, [ 'aa', [ [ 'bold', 'boolean', true ] ], 'AbA', [], 'cc' ])
|
||||
|
||||
// make sure save/load can handle marks
|
||||
|
||||
let doc2 = Automerge.load(doc.save())
|
||||
spans = doc2.spans(list);
|
||||
assert.deepStrictEqual(spans, [ 'aa', [ [ 'bold', 'boolean', true ] ], 'AbA', [], 'cc' ])
|
||||
|
||||
assert.deepStrictEqual(doc.getHeads(), doc2.getHeads())
|
||||
assert.deepStrictEqual(doc.save(), doc2.save())
|
||||
})
|
||||
|
||||
it.only('should handle overlapping marks', () => {
|
||||
|
@ -489,6 +498,17 @@ describe('Automerge', () => {
|
|||
[],
|
||||
]
|
||||
)
|
||||
|
||||
// mark sure encode decode can handle marks
|
||||
|
||||
let all = doc.getChanges([])
|
||||
let decoded = all.map((c) => decodeChange(c))
|
||||
let encoded = decoded.map((c) => encodeChange(c))
|
||||
let doc2 = Automerge.init();
|
||||
doc2.applyChanges(encoded)
|
||||
|
||||
assert.deepStrictEqual(doc.spans(list) , doc2.spans(list))
|
||||
assert.deepStrictEqual(doc.save(), doc2.save())
|
||||
})
|
||||
|
||||
})
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::exid::ExId;
|
|||
use crate::op_set::OpSet;
|
||||
use crate::types::{
|
||||
ActorId, ChangeHash, Clock, ElemId, Export, Exportable, Key, ObjId, Op, OpId, OpType, Patch,
|
||||
ScalarValue, Value, MarkData,
|
||||
ScalarValue, Value,
|
||||
};
|
||||
use crate::{legacy, query, types, ObjType};
|
||||
use crate::{AutomergeError, Change, Prop};
|
||||
|
@ -322,26 +322,25 @@ impl Automerge {
|
|||
value: V,
|
||||
) -> Result<Option<ExId>, AutomergeError> {
|
||||
let obj = self.exid_to_obj(obj)?;
|
||||
if let Some(id) = self.do_insert(obj, index, value)? {
|
||||
let value = value.into();
|
||||
if let Some(id) = self.do_insert(obj, index, value.into())? {
|
||||
Ok(Some(self.id_to_exid(id)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn do_insert<V: Into<Value>>(
|
||||
fn do_insert(
|
||||
&mut self,
|
||||
obj: ObjId,
|
||||
index: usize,
|
||||
value: V,
|
||||
action: OpType,
|
||||
) -> Result<Option<OpId>, AutomergeError> {
|
||||
let id = self.next_id();
|
||||
let value = value.into();
|
||||
|
||||
let query = self.ops.search(obj, query::InsertNth::new(index));
|
||||
|
||||
let key = query.key()?;
|
||||
let action = value.into();
|
||||
let is_make = matches!(&action, OpType::Make(_));
|
||||
|
||||
let op = Op {
|
||||
|
@ -399,7 +398,7 @@ impl Automerge {
|
|||
let mut results = Vec::new();
|
||||
for v in vals {
|
||||
// insert()
|
||||
let id = self.do_insert(obj, pos, v.clone())?;
|
||||
let id = self.do_insert(obj, pos, v.into())?;
|
||||
if let Some(id) = id {
|
||||
results.push(self.id_to_exid(id));
|
||||
}
|
||||
|
@ -465,8 +464,11 @@ impl Automerge {
|
|||
value: ScalarValue,
|
||||
) -> Result<(), AutomergeError> {
|
||||
let obj = self.exid_to_obj(obj)?;
|
||||
let query = self.ops.search(obj, query::Mark::new(start, end));
|
||||
|
||||
self.do_insert(obj, start, OpType::mark(mark.into(), start_sticky, value))?;
|
||||
self.do_insert(obj, end, OpType::Unmark(end_sticky))?;
|
||||
|
||||
/*
|
||||
let (a, b) = query.ops()?;
|
||||
let (pos, key) = a;
|
||||
let id = self.next_id();
|
||||
|
@ -497,6 +499,7 @@ impl Automerge {
|
|||
};
|
||||
self.ops.insert(pos, op.clone());
|
||||
self.tx().operations.push(op);
|
||||
*/
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use std::{
|
|||
str,
|
||||
};
|
||||
|
||||
use crate::types::{ActorId, ElemId, Key, ObjId, ObjType, Op, OpId, OpType, ScalarValue};
|
||||
use crate::types::{ActorId, ElemId, Key, ObjId, ObjType, Op, OpId, OpType, ScalarValue, MarkData };
|
||||
|
||||
use crate::legacy as amp;
|
||||
use amp::SortedVec;
|
||||
|
@ -134,6 +134,15 @@ impl<'a> Iterator for OperationIterator<'a> {
|
|||
Action::MakeTable => OpType::Make(ObjType::Table),
|
||||
Action::Del => OpType::Del,
|
||||
Action::Inc => OpType::Inc(value.to_i64()?),
|
||||
Action::Mark => {
|
||||
// mark has 3 things in the val column
|
||||
let name = value.to_string()?;
|
||||
let sticky = self.value.next()?.to_bool()?;
|
||||
let value = self.value.next()?;
|
||||
OpType::Mark(MarkData { name, sticky, value })
|
||||
}
|
||||
Action::Unmark => OpType::Unmark(value.to_bool()?),
|
||||
Action::Unused => panic!("invalid action"),
|
||||
};
|
||||
Some(amp::Op {
|
||||
action,
|
||||
|
@ -175,6 +184,15 @@ impl<'a> Iterator for DocOpIterator<'a> {
|
|||
Action::MakeTable => OpType::Make(ObjType::Table),
|
||||
Action::Del => OpType::Del,
|
||||
Action::Inc => OpType::Inc(value.to_i64()?),
|
||||
Action::Mark => {
|
||||
// mark has 3 things in the val column
|
||||
let name = value.to_string()?;
|
||||
let sticky = self.value.next()?.to_bool()?;
|
||||
let value = self.value.next()?;
|
||||
OpType::Mark(MarkData { name, sticky, value })
|
||||
}
|
||||
Action::Unmark => OpType::Unmark(value.to_bool()?),
|
||||
Action::Unused => panic!("invalid action"),
|
||||
};
|
||||
Some(DocOp {
|
||||
actor,
|
||||
|
@ -1064,8 +1082,16 @@ impl DocOpEncoder {
|
|||
self.val.append_null();
|
||||
Action::Del
|
||||
}
|
||||
amp::OpType::Mark(_) => unimplemented!(),
|
||||
amp::OpType::Unmark(_) => unimplemented!(),
|
||||
amp::OpType::Mark(m) => {
|
||||
self.val.append_value(&m.name.clone().into(), actors);
|
||||
self.val.append_value(&m.sticky.into(), actors);
|
||||
self.val.append_value(&m.value.clone().into(), actors);
|
||||
Action::Mark
|
||||
}
|
||||
amp::OpType::Unmark(s) => {
|
||||
self.val.append_value(&(*s).into(), actors);
|
||||
Action::Unmark
|
||||
}
|
||||
amp::OpType::Make(kind) => {
|
||||
self.val.append_null();
|
||||
match kind {
|
||||
|
@ -1172,8 +1198,16 @@ impl ColumnEncoder {
|
|||
self.val.append_null();
|
||||
Action::Del
|
||||
}
|
||||
OpType::Mark(_) => unimplemented!(),
|
||||
OpType::Unmark(_) => unimplemented!(),
|
||||
OpType::Mark(m) => {
|
||||
self.val.append_value2(&m.name.clone().into(), actors);
|
||||
self.val.append_value2(&m.sticky.into(), actors);
|
||||
self.val.append_value2(&m.value.clone().into(), actors);
|
||||
Action::Mark
|
||||
}
|
||||
OpType::Unmark(s) => {
|
||||
self.val.append_value2(&(*s).into(), actors);
|
||||
Action::Unmark
|
||||
}
|
||||
OpType::Make(kind) => {
|
||||
self.val.append_null();
|
||||
match kind {
|
||||
|
@ -1279,8 +1313,11 @@ pub(crate) enum Action {
|
|||
MakeText,
|
||||
Inc,
|
||||
MakeTable,
|
||||
Mark,
|
||||
Unused, // final bit is used to mask `Make` actions
|
||||
Unmark,
|
||||
}
|
||||
const ACTIONS: [Action; 7] = [
|
||||
const ACTIONS: [Action; 10] = [
|
||||
Action::MakeMap,
|
||||
Action::Set,
|
||||
Action::MakeList,
|
||||
|
@ -1288,6 +1325,9 @@ const ACTIONS: [Action; 7] = [
|
|||
Action::MakeText,
|
||||
Action::Inc,
|
||||
Action::MakeTable,
|
||||
Action::Mark,
|
||||
Action::Unused,
|
||||
Action::Unmark,
|
||||
];
|
||||
|
||||
impl Decodable for Action {
|
||||
|
|
|
@ -49,6 +49,12 @@ impl Serialize for Op {
|
|||
match &self.action {
|
||||
OpType::Inc(n) => op.serialize_field("value", &n)?,
|
||||
OpType::Set(value) => op.serialize_field("value", &value)?,
|
||||
OpType::Mark(m) => {
|
||||
op.serialize_field("name", &m.name)?;
|
||||
op.serialize_field("sticky", &m.sticky)?;
|
||||
op.serialize_field("value", &m.value)?;
|
||||
}
|
||||
OpType::Unmark(s) => op.serialize_field("sticky", &s)?,
|
||||
_ => {}
|
||||
}
|
||||
op.serialize_field("pred", &self.pred)?;
|
||||
|
@ -70,6 +76,8 @@ pub(crate) enum RawOpType {
|
|||
Del,
|
||||
Inc,
|
||||
Set,
|
||||
Mark,
|
||||
Unmark,
|
||||
}
|
||||
|
||||
impl Serialize for RawOpType {
|
||||
|
@ -85,6 +93,8 @@ impl Serialize for RawOpType {
|
|||
RawOpType::Del => "del",
|
||||
RawOpType::Inc => "inc",
|
||||
RawOpType::Set => "set",
|
||||
RawOpType::Mark => "mark",
|
||||
RawOpType::Unmark => "unmark",
|
||||
};
|
||||
serializer.serialize_str(s)
|
||||
}
|
||||
|
@ -103,6 +113,8 @@ impl<'de> Deserialize<'de> for RawOpType {
|
|||
"del",
|
||||
"inc",
|
||||
"set",
|
||||
"mark",
|
||||
"unmark",
|
||||
];
|
||||
// TODO: Probably more efficient to deserialize to a `&str`
|
||||
let raw_type = String::deserialize(deserializer)?;
|
||||
|
@ -114,6 +126,8 @@ impl<'de> Deserialize<'de> for RawOpType {
|
|||
"del" => Ok(RawOpType::Del),
|
||||
"inc" => Ok(RawOpType::Inc),
|
||||
"set" => Ok(RawOpType::Set),
|
||||
"mark" => Ok(RawOpType::Mark),
|
||||
"unmark" => Ok(RawOpType::Unmark),
|
||||
other => Err(Error::unknown_variant(other, VARIANTS)),
|
||||
}
|
||||
}
|
||||
|
@ -144,6 +158,8 @@ impl<'de> Deserialize<'de> for Op {
|
|||
let mut insert: Option<bool> = None;
|
||||
let mut datatype: Option<DataType> = None;
|
||||
let mut value: Option<Option<ScalarValue>> = None;
|
||||
let mut name: Option<String> = None;
|
||||
let mut sticky: Option<bool> = None;
|
||||
let mut ref_id: Option<OpId> = None;
|
||||
while let Some(field) = map.next_key::<String>()? {
|
||||
match field.as_ref() {
|
||||
|
@ -167,6 +183,8 @@ impl<'de> Deserialize<'de> for Op {
|
|||
"insert" => read_field("insert", &mut insert, &mut map)?,
|
||||
"datatype" => read_field("datatype", &mut datatype, &mut map)?,
|
||||
"value" => read_field("value", &mut value, &mut map)?,
|
||||
"name" => read_field("name", &mut name, &mut map)?,
|
||||
"sticky" => read_field("sticky", &mut sticky, &mut map)?,
|
||||
"ref" => read_field("ref", &mut ref_id, &mut map)?,
|
||||
_ => return Err(Error::unknown_field(&field, FIELDS)),
|
||||
}
|
||||
|
@ -182,6 +200,30 @@ impl<'de> Deserialize<'de> for Op {
|
|||
RawOpType::MakeList => OpType::Make(ObjType::List),
|
||||
RawOpType::MakeText => OpType::Make(ObjType::Text),
|
||||
RawOpType::Del => OpType::Del,
|
||||
RawOpType::Mark => {
|
||||
let name = name.ok_or_else(|| Error::missing_field("mark(name)"))?;
|
||||
let sticky = sticky.unwrap_or(false);
|
||||
let value = if let Some(datatype) = datatype {
|
||||
let raw_value = value
|
||||
.ok_or_else(|| Error::missing_field("value"))?
|
||||
.unwrap_or(ScalarValue::Null);
|
||||
raw_value.as_datatype(datatype).map_err(|e| {
|
||||
Error::invalid_value(
|
||||
Unexpected::Other(e.unexpected.as_str()),
|
||||
&e.expected.as_str(),
|
||||
)
|
||||
})?
|
||||
} else {
|
||||
value
|
||||
.ok_or_else(|| Error::missing_field("value"))?
|
||||
.unwrap_or(ScalarValue::Null)
|
||||
};
|
||||
OpType::mark(name, sticky, value)
|
||||
}
|
||||
RawOpType::Unmark => {
|
||||
let sticky = sticky.unwrap_or(true);
|
||||
OpType::Unmark(sticky)
|
||||
}
|
||||
RawOpType::Set => {
|
||||
let value = if let Some(datatype) = datatype {
|
||||
let raw_value = value
|
||||
|
|
|
@ -15,8 +15,8 @@ impl Serialize for OpType {
|
|||
OpType::Make(ObjType::Table) => RawOpType::MakeTable,
|
||||
OpType::Make(ObjType::List) => RawOpType::MakeList,
|
||||
OpType::Make(ObjType::Text) => RawOpType::MakeText,
|
||||
OpType::Mark(_) => unimplemented!(),
|
||||
OpType::Unmark(_) => unimplemented!(),
|
||||
OpType::Mark(_) => RawOpType::Mark,
|
||||
OpType::Unmark(_) => RawOpType::Unmark,
|
||||
OpType::Del => RawOpType::Del,
|
||||
OpType::Inc(_) => RawOpType::Inc,
|
||||
OpType::Set(_) => RawOpType::Set,
|
||||
|
|
|
@ -2,4 +2,3 @@ mod element_id;
|
|||
mod key;
|
||||
mod object_id;
|
||||
mod opid;
|
||||
mod scalar_value;
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
use std::fmt;
|
||||
|
||||
use smol_str::SmolStr;
|
||||
|
||||
use crate::value::ScalarValue;
|
||||
|
||||
impl From<&str> for ScalarValue {
|
||||
fn from(s: &str) -> Self {
|
||||
ScalarValue::Str(s.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for ScalarValue {
|
||||
fn from(n: i64) -> Self {
|
||||
ScalarValue::Int(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for ScalarValue {
|
||||
fn from(n: u64) -> Self {
|
||||
ScalarValue::Uint(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for ScalarValue {
|
||||
fn from(n: i32) -> Self {
|
||||
ScalarValue::Int(n as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for ScalarValue {
|
||||
fn from(b: bool) -> Self {
|
||||
ScalarValue::Boolean(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<char> for ScalarValue {
|
||||
fn from(c: char) -> Self {
|
||||
ScalarValue::Str(SmolStr::new(c.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ScalarValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ScalarValue::Bytes(b) => write!(f, "\"{:?}\"", b),
|
||||
ScalarValue::Str(s) => write!(f, "\"{}\"", s),
|
||||
ScalarValue::Int(i) => write!(f, "{}", i),
|
||||
ScalarValue::Uint(i) => write!(f, "{}", i),
|
||||
ScalarValue::F64(n) => write!(f, "{:.324}", n),
|
||||
ScalarValue::Counter(c) => write!(f, "Counter: {}", c),
|
||||
ScalarValue::Timestamp(i) => write!(f, "Timestamp: {}", i),
|
||||
ScalarValue::Boolean(b) => write!(f, "{}", b),
|
||||
ScalarValue::Null => write!(f, "null"),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ mod len;
|
|||
mod len_at;
|
||||
mod list_vals;
|
||||
mod list_vals_at;
|
||||
mod mark;
|
||||
mod nth;
|
||||
mod nth_at;
|
||||
mod prop;
|
||||
|
@ -27,7 +26,6 @@ pub(crate) use len::Len;
|
|||
pub(crate) use len_at::LenAt;
|
||||
pub(crate) use list_vals::ListVals;
|
||||
pub(crate) use list_vals_at::ListValsAt;
|
||||
pub(crate) use mark::Mark;
|
||||
pub(crate) use nth::Nth;
|
||||
pub(crate) use nth_at::NthAt;
|
||||
pub(crate) use prop::Prop;
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
use crate::AutomergeError;
|
||||
use crate::query::{QueryResult, TreeQuery};
|
||||
use crate::types::{ElemId, Key, Op};
|
||||
use std::fmt::Debug;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub(crate) struct Mark<const B: usize> {
|
||||
start: usize,
|
||||
end: usize,
|
||||
pos: usize,
|
||||
seen: usize,
|
||||
_ops: Vec<(usize, Key)>,
|
||||
count: usize,
|
||||
last_seen: Option<ElemId>,
|
||||
last_insert: Option<ElemId>,
|
||||
}
|
||||
|
||||
impl<const B: usize> Mark<B> {
|
||||
pub fn new(start: usize, end: usize) -> Self {
|
||||
Mark {
|
||||
start,
|
||||
end,
|
||||
pos: 0,
|
||||
seen: 0,
|
||||
_ops: Vec::new(),
|
||||
count: 0,
|
||||
last_seen: None,
|
||||
last_insert: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ops(&self) -> Result<((usize,Key),(usize,Key)),AutomergeError> {
|
||||
if self._ops.len() == 2 {
|
||||
Ok((self._ops[0], self._ops[1]))
|
||||
} else if self._ops.len() == 1 {
|
||||
Ok((self._ops[0], (self.pos + 1, self.last_insert.into())))
|
||||
} else {
|
||||
Err(AutomergeError::Fail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const B: usize> TreeQuery<B> for Mark<B> {
|
||||
/*
|
||||
fn query_node(&mut self, _child: &OpTreeNode<B>) -> QueryResult {
|
||||
unimplemented!()
|
||||
}
|
||||
*/
|
||||
|
||||
fn query_element(&mut self, element: &Op) -> QueryResult {
|
||||
// find location to insert
|
||||
// mark or set
|
||||
if element.insert {
|
||||
if self.seen >= self.end {
|
||||
self._ops.push((self.pos + 1, self.last_insert.into()));
|
||||
return QueryResult::Finish;
|
||||
}
|
||||
if self.seen >= self.start && self._ops.is_empty() {
|
||||
self._ops.push((self.pos, self.last_insert.into()));
|
||||
}
|
||||
self.last_seen = None;
|
||||
self.last_insert = element.elemid();
|
||||
}
|
||||
if self.last_seen.is_none() && element.visible() {
|
||||
self.seen += 1;
|
||||
self.last_seen = element.elemid()
|
||||
}
|
||||
self.pos += 1;
|
||||
QueryResult::Next
|
||||
}
|
||||
}
|
|
@ -53,9 +53,11 @@ impl<const B: usize> Spans<B> {
|
|||
if self.changed && (self.seen_at_last_mark != self.seen_at_this_mark || self.seen_at_last_mark.is_none() && self.seen_at_this_mark.is_none()) {
|
||||
self.changed = false;
|
||||
self.seen_at_last_mark = self.seen_at_this_mark;
|
||||
let mut marks : Vec<_> = self.marks.iter().map(|(key, val)| (key.clone(), val.clone())).collect();
|
||||
marks.sort_by(|(k1,_),(k2,_)| k1.cmp(k2));
|
||||
self.spans.push(Span {
|
||||
pos: self.seen,
|
||||
marks: self.marks.iter().map(|(key, val)| (key.clone(), val.clone())).collect()
|
||||
marks,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,6 +164,12 @@ pub enum OpType {
|
|||
Unmark(bool),
|
||||
}
|
||||
|
||||
impl OpType {
|
||||
pub (crate) fn mark(name: String, sticky: bool, value: ScalarValue) -> Self {
|
||||
OpType::Mark(MarkData { name, sticky, value })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone)]
|
||||
pub struct MarkData {
|
||||
pub name: String,
|
||||
|
|
|
@ -375,7 +375,79 @@ impl ScalarValue {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn to_bool(self) -> Option<bool> {
|
||||
match self {
|
||||
ScalarValue::Boolean(b) => Some(b),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_string(self) -> Option<String> {
|
||||
match self {
|
||||
ScalarValue::Str(s) => Some(s.to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn counter(n: i64) -> ScalarValue {
|
||||
ScalarValue::Counter(n.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ScalarValue {
|
||||
fn from(s: &str) -> Self {
|
||||
ScalarValue::Str(s.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for ScalarValue {
|
||||
fn from(s: String) -> Self {
|
||||
ScalarValue::Str(s.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for ScalarValue {
|
||||
fn from(n: i64) -> Self {
|
||||
ScalarValue::Int(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for ScalarValue {
|
||||
fn from(n: u64) -> Self {
|
||||
ScalarValue::Uint(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for ScalarValue {
|
||||
fn from(n: i32) -> Self {
|
||||
ScalarValue::Int(n as i64)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for ScalarValue {
|
||||
fn from(b: bool) -> Self {
|
||||
ScalarValue::Boolean(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<char> for ScalarValue {
|
||||
fn from(c: char) -> Self {
|
||||
ScalarValue::Str(SmolStr::new(c.to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ScalarValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ScalarValue::Bytes(b) => write!(f, "\"{:?}\"", b),
|
||||
ScalarValue::Str(s) => write!(f, "\"{}\"", s),
|
||||
ScalarValue::Int(i) => write!(f, "{}", i),
|
||||
ScalarValue::Uint(i) => write!(f, "{}", i),
|
||||
ScalarValue::F64(n) => write!(f, "{:.324}", n),
|
||||
ScalarValue::Counter(c) => write!(f, "Counter: {}", c),
|
||||
ScalarValue::Timestamp(i) => write!(f, "Timestamp: {}", i),
|
||||
ScalarValue::Boolean(b) => write!(f, "{}", b),
|
||||
ScalarValue::Null => write!(f, "null"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue