Experimental WIP
This commit is contained in:
parent
ce9d4f2f0c
commit
c053e2b9dd
|
@ -13,7 +13,7 @@ gitlab = { repository = "preserves/preserves" }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
bytemuck = "1.12"
|
bytemuck = { version = "1.12", features = ["extern_crate_alloc"] }
|
||||||
dtoa = "0.4"
|
dtoa = "0.4"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
num-bigint = "0.4"
|
num-bigint = "0.4"
|
||||||
|
|
|
@ -6,7 +6,6 @@ use std::io;
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
Message(String),
|
Message(String),
|
||||||
InvalidUnicodeScalar(u32),
|
|
||||||
NumberOutOfRange(BigInt),
|
NumberOutOfRange(BigInt),
|
||||||
MissingCloseDelimiter,
|
MissingCloseDelimiter,
|
||||||
MissingItem,
|
MissingItem,
|
||||||
|
@ -34,8 +33,6 @@ pub enum ExpectedKind {
|
||||||
|
|
||||||
Embedded,
|
Embedded,
|
||||||
|
|
||||||
Option,
|
|
||||||
UnicodeScalar,
|
|
||||||
Annotation,
|
Annotation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,53 +3,49 @@ pub mod domain;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod float;
|
pub mod float;
|
||||||
pub mod hex;
|
pub mod hex;
|
||||||
pub mod packed;
|
pub mod merge;
|
||||||
|
// pub mod packed;
|
||||||
pub mod reader;
|
pub mod reader;
|
||||||
pub mod repr;
|
pub mod repr;
|
||||||
pub mod signed_integer;
|
pub mod signed_integer;
|
||||||
pub mod source;
|
pub mod source;
|
||||||
pub mod text;
|
// pub mod text;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
pub mod writer;
|
pub mod writer;
|
||||||
|
|
||||||
pub use domain::*;
|
pub use domain::*;
|
||||||
pub use packed::PackedReader;
|
pub use error::Error;
|
||||||
pub use packed::PackedWriter;
|
pub use error::ExpectedKind;
|
||||||
pub use packed::annotated_from_bytes;
|
pub use merge::merge;
|
||||||
pub use packed::annotated_iovalue_from_bytes;
|
pub use merge::merge2;
|
||||||
pub use packed::from_bytes;
|
// pub use packed::PackedReader;
|
||||||
pub use packed::iovalue_from_bytes;
|
// pub use packed::PackedWriter;
|
||||||
|
// pub use packed::annotated_from_bytes;
|
||||||
|
// pub use packed::annotated_iovalue_from_bytes;
|
||||||
|
// pub use packed::from_bytes;
|
||||||
|
// pub use packed::iovalue_from_bytes;
|
||||||
pub use reader::IOValues;
|
pub use reader::IOValues;
|
||||||
pub use reader::Reader;
|
pub use reader::Reader;
|
||||||
pub use repr::Annotations;
|
pub use repr::Annotations;
|
||||||
pub use repr::ArcValue;
|
pub use repr::ArcValue;
|
||||||
pub use repr::Atom;
|
pub use repr::Atom;
|
||||||
pub use repr::Bytes;
|
|
||||||
pub use repr::Embedded;
|
|
||||||
pub use repr::IOValue;
|
pub use repr::IOValue;
|
||||||
pub use repr::Map;
|
pub use repr::Map;
|
||||||
pub use repr::PlainValue;
|
|
||||||
pub use repr::NoValue;
|
pub use repr::NoValue;
|
||||||
pub use repr::Record;
|
pub use repr::Record;
|
||||||
pub use repr::Set;
|
pub use repr::Set;
|
||||||
pub use repr::Symbol;
|
|
||||||
pub use repr::Value;
|
pub use repr::Value;
|
||||||
pub use repr::ValueImpl;
|
pub use repr::ValueImpl;
|
||||||
pub use repr::copy_via;
|
|
||||||
pub use repr::iovalue;
|
|
||||||
pub use repr::owned;
|
|
||||||
pub use repr::shell;
|
|
||||||
pub use repr::value;
|
|
||||||
pub use signed_integer::SignedInteger;
|
pub use signed_integer::SignedInteger;
|
||||||
pub use source::BinarySource;
|
pub use source::BinarySource;
|
||||||
pub use source::BytesBinarySource;
|
pub use source::BytesBinarySource;
|
||||||
pub use source::IOBinarySource;
|
pub use source::IOBinarySource;
|
||||||
pub use text::TextReader;
|
// pub use text::TextReader;
|
||||||
pub use text::TextWriter;
|
// pub use text::TextWriter;
|
||||||
pub use text::annotated_from_str;
|
// pub use text::annotated_from_str;
|
||||||
pub use text::annotated_iovalue_from_str;
|
// pub use text::annotated_iovalue_from_str;
|
||||||
pub use text::from_str;
|
// pub use text::from_str;
|
||||||
pub use text::iovalue_from_str;
|
// pub use text::iovalue_from_str;
|
||||||
pub use types::AtomClass;
|
pub use types::AtomClass;
|
||||||
pub use types::CompoundClass;
|
pub use types::CompoundClass;
|
||||||
pub use types::ValueClass;
|
pub use types::ValueClass;
|
||||||
|
@ -64,45 +60,45 @@ mod demo {
|
||||||
// d.get(&k)
|
// d.get(&k)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[test] fn a() {
|
// #[test] fn a() {
|
||||||
let l: PlainValue<NoValue> = "label".parse().unwrap();
|
// let l: PlainValue<NoValue> = "label".parse().unwrap();
|
||||||
let r = Record::new(l.value_clone(), vec![owned(1), owned(2), owned(3)]);
|
// let r = Record::new(l.value_clone(), vec![owned(1), owned(2), owned(3)]);
|
||||||
let r2 = Record::new(l, vec![owned(1), owned(2), owned(4)]);
|
// let r2 = Record::new(l, vec![owned(1), owned(2), owned(4)]);
|
||||||
|
|
||||||
let mut v: Map<PlainValue<NoValue>, PlainValue<NoValue>> = Map::new();
|
// let mut v: Map<PlainValue<NoValue>, PlainValue<NoValue>> = Map::new();
|
||||||
v.insert("\"abc\"".parse().unwrap(), "def".parse().unwrap());
|
// v.insert("\"abc\"".parse().unwrap(), "def".parse().unwrap());
|
||||||
v.insert("abc".parse().unwrap(), "DEF".parse().unwrap());
|
// v.insert("abc".parse().unwrap(), "DEF".parse().unwrap());
|
||||||
v.insert(owned(123), "xyz".parse().unwrap());
|
// v.insert(owned(123), "xyz".parse().unwrap());
|
||||||
v.insert(owned(vec![1, 2, 3]), "{a: 1, b: 2}".parse().unwrap());
|
// v.insert(owned(vec![1, 2, 3]), "{a: 1, b: 2}".parse().unwrap());
|
||||||
v.insert(owned(r2), "bbb".parse().unwrap());
|
// v.insert(owned(r2), "bbb".parse().unwrap());
|
||||||
v.insert(owned(r), "<foo bar zot>".parse().unwrap());
|
// v.insert(owned(r), "<foo bar zot>".parse().unwrap());
|
||||||
let w: &dyn ValueImpl<NoValue> = &v;
|
// let w: &dyn ValueImpl<NoValue> = &v;
|
||||||
println!("GETw abc {:?}", w.get(&"abc"));
|
// println!("GETw abc {:?}", w.get(&"abc"));
|
||||||
println!("GETw 123 {:?}", w.get(&123));
|
// println!("GETw 123 {:?}", w.get(&123));
|
||||||
println!("GETw qqq {:?}", w.get(&"qqq"));
|
// println!("GETw qqq {:?}", w.get(&"qqq"));
|
||||||
println!("GETv abc {:?}", v.get(&*value(&"abc")));
|
// println!("GETv abc {:?}", v.get(&*value(&"abc")));
|
||||||
println!("GETv 123 {:?}", v.get(&*value(&123)));
|
// println!("GETv 123 {:?}", v.get(&*value(&123)));
|
||||||
println!("GETv qqq {:?}", v.get(&*value(&"qqq")));
|
// println!("GETv qqq {:?}", v.get(&*value(&"qqq")));
|
||||||
for (kk, vv) in w.entries() {
|
// for (kk, vv) in w.entries() {
|
||||||
println!("{:#?} ==> {:#?}", kk, vv);
|
// println!("{:#?} ==> {:#?}", kk, vv);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// {
|
// // {
|
||||||
// use std::io::BufRead;
|
// // use std::io::BufRead;
|
||||||
// for line in std::io::stdin().lock().lines() {
|
// // for line in std::io::stdin().lock().lines() {
|
||||||
// let line = line.unwrap();
|
// // let line = line.unwrap();
|
||||||
// let key = line.parse::<PlainValue<NoValue>>().unwrap();
|
// // let key = line.parse::<PlainValue<NoValue>>().unwrap();
|
||||||
// let val = w.get(&key);
|
// // let val = w.get(&key);
|
||||||
// println!("{:?} == {:?} ==> {:?} == {:?}", line, &key, val, getit(&v, &line));
|
// // println!("{:?} == {:?} ==> {:?} == {:?}", line, &key, val, getit(&v, &line));
|
||||||
// }
|
// // }
|
||||||
// }
|
// // }
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[test] fn value_size() {
|
// #[test] fn value_size() {
|
||||||
println!("Value size {}", std::mem::size_of::<Value<'_, NoValue>>());
|
// println!("Value size {}", std::mem::size_of::<Value<'_, NoValue>>());
|
||||||
println!("&dyn ValueImpl size {}", std::mem::size_of::<&dyn ValueImpl<NoValue>>());
|
// println!("&dyn ValueImpl size {}", std::mem::size_of::<&dyn ValueImpl<NoValue>>());
|
||||||
println!("Box dyn ValueImpl size {}", std::mem::size_of::<Box<dyn ValueImpl<NoValue>>>());
|
// println!("Box dyn ValueImpl size {}", std::mem::size_of::<Box<dyn ValueImpl<NoValue>>>());
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,64 +1,89 @@
|
||||||
use super::Map;
|
use crate::Annotations;
|
||||||
use super::NestedValue;
|
use crate::ArcValue;
|
||||||
use super::Record;
|
use crate::CompoundClass;
|
||||||
use super::Value;
|
use crate::Map;
|
||||||
|
use crate::Record;
|
||||||
|
use crate::Value;
|
||||||
|
use crate::ValueClass;
|
||||||
|
use crate::ValueImpl;
|
||||||
|
|
||||||
pub fn merge_seqs<N: NestedValue>(mut a: Vec<N>, mut b: Vec<N>) -> Option<Vec<N>> {
|
pub fn merge_seqs<V: ValueImpl, W: ValueImpl<Embedded = V::Embedded>>(
|
||||||
|
mut a: Vec<Value<V>>,
|
||||||
|
mut b: Vec<Value<W>>,
|
||||||
|
) -> Option<Vec<ArcValue<V::Embedded>>> {
|
||||||
if a.len() > b.len() {
|
if a.len() > b.len() {
|
||||||
std::mem::swap(&mut a, &mut b);
|
std::mem::swap(&mut a, &mut b);
|
||||||
}
|
}
|
||||||
let mut r = vec![];
|
let mut r = vec![];
|
||||||
let mut bi = b.into_iter();
|
let mut bi = b.into_iter();
|
||||||
for av in a.into_iter() {
|
for av in a.into_iter() {
|
||||||
r.push(merge2(av, bi.next().unwrap())?);
|
r.push(merge2(&*av, &*bi.next().unwrap())?);
|
||||||
}
|
}
|
||||||
r.extend(bi);
|
r.extend(bi.map(|bv| bv.value_clone()));
|
||||||
Some(r)
|
Some(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge2<N: NestedValue>(v: N, w: N) -> Option<N> {
|
pub fn merge2<V: ValueImpl, W: ValueImpl<Embedded = V::Embedded>>(v: &Value<V>, w: &Value<W>) -> Option<ArcValue<V::Embedded>> {
|
||||||
let (mut v_anns, v_val) = v.pieces();
|
let anns = match (v.annotations(), w.annotations()) {
|
||||||
let (w_anns, w_val) = w.pieces();
|
(Some(va), Some(wa)) => {
|
||||||
match &mut v_anns {
|
let mut a = va.to_vec();
|
||||||
None => v_anns = w_anns,
|
a.extend(wa.to_vec());
|
||||||
Some(vs) => match w_anns {
|
a
|
||||||
None => (),
|
|
||||||
Some(ws) => vs.extend(ws.into_iter()),
|
|
||||||
}
|
}
|
||||||
}
|
(Some(va), None) => va.to_vec(),
|
||||||
if v_val == w_val {
|
(None, Some(wa)) => wa.to_vec(),
|
||||||
Some(N::wrap(v_anns, v_val))
|
(None, None) => vec![],
|
||||||
|
};
|
||||||
|
|
||||||
|
let r = if v == w {
|
||||||
|
Some(v.peeled().value_clone())
|
||||||
} else {
|
} else {
|
||||||
let maybe_merged = match v_val {
|
match v.value_class() {
|
||||||
Value::Record(rv) =>
|
ValueClass::Atomic(_) => None,
|
||||||
Some(Value::Record(Record(merge_seqs(rv.0, w_val.into_record()?.0)?))),
|
ValueClass::Embedded => None,
|
||||||
Value::Sequence(vs) =>
|
ValueClass::Compound(CompoundClass::Record) => if w.is_record() {
|
||||||
Some(Value::Sequence(merge_seqs(vs, w_val.into_sequence()?)?)),
|
todo!()
|
||||||
Value::Set(_vs) =>
|
// Some(owned(Record::new(merge2(&*v.label(), &*w.label())?,
|
||||||
|
// merge_seqs(v.iter().collect(), w.iter().collect())?)))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
ValueClass::Compound(CompoundClass::Sequence) => if w.is_sequence() {
|
||||||
|
Some(owned(merge_seqs(v.iter().collect(), w.iter().collect())?))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
ValueClass::Compound(CompoundClass::Set) =>
|
||||||
None, // unsure how to merge sets
|
None, // unsure how to merge sets
|
||||||
Value::Dictionary(vs) => {
|
ValueClass::Compound(CompoundClass::Dictionary) => if w.is_dictionary() {
|
||||||
let mut ws = w_val.into_dictionary()?;
|
let mut ws: Map<_, _> = w.entries().collect();
|
||||||
let mut rs = Map::new();
|
let mut rs = Map::new();
|
||||||
for (k, vv) in vs.into_iter() {
|
for (k, vv) in v.entries() {
|
||||||
match ws.remove(&k) {
|
match ws.remove(&k) {
|
||||||
Some(wv) => { rs.insert(k, merge2(vv, wv)?); }
|
Some(wv) => { rs.insert(k.value_clone(), merge2(&*vv, &*wv)?); }
|
||||||
None => { rs.insert(k, vv); }
|
None => { rs.insert(k.value_clone(), vv.value_clone()); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rs.extend(ws.into_iter());
|
rs.extend(ws.into_iter().map(|(k, wv)| (k.value_clone(), wv.value_clone())));
|
||||||
Some(Value::Dictionary(rs))
|
Some(owned(rs))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
_ => None,
|
}
|
||||||
};
|
};
|
||||||
maybe_merged.map(|vw| N::wrap(v_anns, vw))
|
|
||||||
}
|
r.map(|r| if anns.is_empty() {
|
||||||
|
r
|
||||||
|
} else {
|
||||||
|
owned(Annotations::new(r, anns))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn merge<N: NestedValue, I: IntoIterator<Item = N>>(vs: I) -> Option<N> {
|
pub fn merge<V: ValueImpl, I: IntoIterator<Item = Value<V>>>(vs: I) -> Option<ArcValue<V::Embedded>> {
|
||||||
let mut vs = vs.into_iter();
|
let mut vs = vs.into_iter();
|
||||||
let mut v = vs.next().expect("at least one value in merge()");
|
let mut v = vs.next().expect("at least one value in merge()").value_clone();
|
||||||
for w in vs {
|
for w in vs {
|
||||||
match merge2(v, w) {
|
match merge2(&*v, &*w) {
|
||||||
Some(merged) => v = merged,
|
Some(merged) => v = merged,
|
||||||
None => return None,
|
None => return None,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod reader;
|
pub mod reader;
|
||||||
pub mod view;
|
// pub mod view;
|
||||||
pub mod writer;
|
pub mod writer;
|
||||||
|
|
||||||
pub use reader::PackedReader;
|
pub use reader::PackedReader;
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::convert::TryInto;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use super::constants::Tag;
|
use super::constants::Tag;
|
||||||
use crate::{boundary as B, ValueImpl, Domain, DomainEncode, IOValue, IOValueDomainCodec, Writer};
|
use crate::{boundary as B, ValueImpl, DomainEncode, IOValue, IOValueDomainCodec, Writer};
|
||||||
|
|
||||||
struct Buffers<W: io::Write> {
|
struct Buffers<W: io::Write> {
|
||||||
base: W,
|
base: W,
|
||||||
|
@ -36,9 +36,9 @@ pub struct PackedWriter<W: io::Write>(Buffers<W>);
|
||||||
|
|
||||||
impl PackedWriter<&mut Vec<u8>> {
|
impl PackedWriter<&mut Vec<u8>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn encode<D: Domain, Enc: DomainEncode<D>>(
|
pub fn encode<V: ValueImpl, Enc: DomainEncode<V::Embedded>>(
|
||||||
enc: &mut Enc,
|
enc: &mut Enc,
|
||||||
v: &dyn ValueImpl<D>,
|
v: &V,
|
||||||
) -> io::Result<Vec<u8>> {
|
) -> io::Result<Vec<u8>> {
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
v.write(&mut PackedWriter::new(&mut buf), enc)?;
|
v.write(&mut PackedWriter::new(&mut buf), enc)?;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,8 +7,17 @@ use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct OutOfRange(pub BigInt);
|
pub struct OutOfRange(pub BigInt);
|
||||||
|
|
||||||
|
impl fmt::Display for OutOfRange {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "The value {:?} is out of range", &self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for OutOfRange {}
|
||||||
|
|
||||||
impl From<OutOfRange> for crate::error::Error {
|
impl From<OutOfRange> for crate::error::Error {
|
||||||
fn from(e: OutOfRange) -> Self {
|
fn from(e: OutOfRange) -> Self {
|
||||||
crate::error::Error::NumberOutOfRange(e.0)
|
crate::error::Error::NumberOutOfRange(e.0)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
use crate::Domain;
|
|
||||||
use crate::DomainEncode;
|
use crate::DomainEncode;
|
||||||
use crate::IOValue;
|
use crate::IOValue;
|
||||||
use crate::IOValueDomainCodec;
|
use crate::IOValueDomainCodec;
|
||||||
|
@ -36,10 +35,10 @@ impl std::default::Default for CommaStyle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextWriter<&mut Vec<u8>> {
|
impl TextWriter<&mut Vec<u8>> {
|
||||||
pub fn fmt_value<D: Domain, Enc: DomainEncode<D>>(
|
pub fn fmt_value<V: ValueImpl, Enc: DomainEncode<V::Embedded>>(
|
||||||
f: &mut std::fmt::Formatter<'_>,
|
f: &mut std::fmt::Formatter<'_>,
|
||||||
enc: &mut Enc,
|
enc: &mut Enc,
|
||||||
v: &dyn ValueImpl<D>,
|
v: &V,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
let mut w = TextWriter::new(&mut buf);
|
let mut w = TextWriter::new(&mut buf);
|
||||||
|
@ -49,9 +48,9 @@ impl TextWriter<&mut Vec<u8>> {
|
||||||
|_| io::Error::new(io::ErrorKind::Other, "could not append to Formatter"))
|
|_| io::Error::new(io::ErrorKind::Other, "could not append to Formatter"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn encode<D: Domain, Enc: DomainEncode<D>>(
|
pub fn encode<V: ValueImpl, Enc: DomainEncode<V::Embedded>>(
|
||||||
enc: &mut Enc,
|
enc: &mut Enc,
|
||||||
v: &dyn ValueImpl<D>,
|
v: &V,
|
||||||
) -> io::Result<String> {
|
) -> io::Result<String> {
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
v.write(&mut TextWriter::new(&mut buf), enc)?;
|
v.write(&mut TextWriter::new(&mut buf), enc)?;
|
||||||
|
|
|
@ -3,7 +3,6 @@ use std::io;
|
||||||
|
|
||||||
use crate::AtomClass;
|
use crate::AtomClass;
|
||||||
use crate::CompoundClass;
|
use crate::CompoundClass;
|
||||||
use crate::Domain;
|
|
||||||
use crate::DomainEncode;
|
use crate::DomainEncode;
|
||||||
use crate::IOValueDomainCodec;
|
use crate::IOValueDomainCodec;
|
||||||
use crate::SignedInteger;
|
use crate::SignedInteger;
|
||||||
|
@ -70,10 +69,10 @@ pub trait Writer {
|
||||||
fn specialized(&mut self) -> Option<(&str, &mut dyn io::Write)> { None }
|
fn specialized(&mut self) -> Option<(&str, &mut dyn io::Write)> { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_value<D: Domain, V: ValueImpl<D>>(
|
pub fn write_value<V: ValueImpl>(
|
||||||
w: &mut dyn Writer,
|
w: &mut dyn Writer,
|
||||||
v: V,
|
v: &V,
|
||||||
enc: &mut dyn DomainEncode<D>,
|
enc: &mut dyn DomainEncode<V::Embedded>,
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let annotations = v.annotations();
|
let annotations = v.annotations();
|
||||||
let mut annotation_b = B::Type::default();
|
let mut annotation_b = B::Type::default();
|
||||||
|
|
Loading…
Reference in New Issue