Introduce ValueRc as an abstraction over Rc/Arc choice.

This commit is contained in:
Richard Newman 2018-04-25 12:22:15 -07:00
parent 9292867dc9
commit 1918388ddf
9 changed files with 64 additions and 39 deletions

View file

@ -56,11 +56,13 @@ mod sql_types;
pub use types::{ pub use types::{
Entid, Entid,
FromRc,
KnownEntid, KnownEntid,
TypedValue, TypedValue,
Binding, Binding,
ValueType, ValueType,
ValueTypeTag, ValueTypeTag,
ValueRc,
now, now,
}; };

View file

@ -72,6 +72,11 @@ impl<T> FromRc<T> for Arc<T> where T: Sized + Clone {
} }
} }
//
// Use Rc for values.
//
pub type ValueRc<T> = Rc<T>;
/// Represents one entid in the entid space. /// Represents one entid in the entid space.
/// ///
/// Per https://www.sqlite.org/datatype3.html (see also http://stackoverflow.com/a/8499544), SQLite /// Per https://www.sqlite.org/datatype3.html (see also http://stackoverflow.com/a/8499544), SQLite
@ -208,8 +213,8 @@ pub enum TypedValue {
Double(OrderedFloat<f64>), Double(OrderedFloat<f64>),
Instant(DateTime<Utc>), // Use `into()` to ensure truncation. Instant(DateTime<Utc>), // Use `into()` to ensure truncation.
// TODO: &str throughout? // TODO: &str throughout?
String(Rc<String>), String(ValueRc<String>),
Keyword(Rc<NamespacedKeyword>), Keyword(ValueRc<NamespacedKeyword>),
Uuid(Uuid), // It's only 128 bits, so this should be acceptable to clone. Uuid(Uuid), // It's only 128 bits, so this should be acceptable to clone.
} }
@ -228,8 +233,8 @@ pub enum TypedValue {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum Binding { pub enum Binding {
Scalar(TypedValue), Scalar(TypedValue),
Vec(Rc<Vec<Binding>>), Vec(ValueRc<Vec<Binding>>),
Map(Rc<StructuredMap>), Map(ValueRc<StructuredMap>),
} }
impl<T> From<T> for Binding where T: Into<TypedValue> { impl<T> From<T> for Binding where T: Into<TypedValue> {
@ -258,7 +263,7 @@ impl Binding {
/// We entirely support the former, and partially support the latter -- you can alias /// We entirely support the former, and partially support the latter -- you can alias
/// using a different keyword only. /// using a different keyword only.
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
pub struct StructuredMap(IndexMap<Rc<NamespacedKeyword>, Binding>); pub struct StructuredMap(IndexMap<ValueRc<NamespacedKeyword>, Binding>);
impl Binding { impl Binding {
/// Returns true if the provided type is `Some` and matches this value's type, or if the /// Returns true if the provided type is `Some` and matches this value's type, or if the
@ -311,14 +316,14 @@ impl TypedValue {
} }
/// Construct a new `TypedValue::Keyword` instance by cloning the provided /// Construct a new `TypedValue::Keyword` instance by cloning the provided
/// values and wrapping them in a new `Rc`. This is expensive, so this might /// values and wrapping them in a new `ValueRc`. This is expensive, so this might
/// be best limited to tests. /// be best limited to tests.
pub fn typed_ns_keyword(ns: &str, name: &str) -> TypedValue { pub fn typed_ns_keyword(ns: &str, name: &str) -> TypedValue {
NamespacedKeyword::new(ns, name).into() NamespacedKeyword::new(ns, name).into()
} }
/// Construct a new `TypedValue::String` instance by cloning the provided /// Construct a new `TypedValue::String` instance by cloning the provided
/// value and wrapping it in a new `Rc`. This is expensive, so this might /// value and wrapping it in a new `ValueRc`. This is expensive, so this might
/// be best limited to tests. /// be best limited to tests.
pub fn typed_string(s: &str) -> TypedValue { pub fn typed_string(s: &str) -> TypedValue {
s.into() s.into()
@ -381,31 +386,43 @@ impl From<Uuid> for TypedValue {
impl<'a> From<&'a str> for TypedValue { impl<'a> From<&'a str> for TypedValue {
fn from(value: &'a str) -> TypedValue { fn from(value: &'a str) -> TypedValue {
TypedValue::String(Rc::new(value.to_string())) TypedValue::String(ValueRc::new(value.to_string()))
}
}
impl From<Arc<String>> for TypedValue {
fn from(value: Arc<String>) -> TypedValue {
TypedValue::String(ValueRc::from_arc(value))
} }
} }
impl From<Rc<String>> for TypedValue { impl From<Rc<String>> for TypedValue {
fn from(value: Rc<String>) -> TypedValue { fn from(value: Rc<String>) -> TypedValue {
TypedValue::String(value.clone()) TypedValue::String(ValueRc::from_rc(value))
} }
} }
impl From<String> for TypedValue { impl From<String> for TypedValue {
fn from(value: String) -> TypedValue { fn from(value: String) -> TypedValue {
TypedValue::String(Rc::new(value)) TypedValue::String(ValueRc::new(value))
}
}
impl From<Arc<NamespacedKeyword>> for TypedValue {
fn from(value: Arc<NamespacedKeyword>) -> TypedValue {
TypedValue::Keyword(ValueRc::from_arc(value))
} }
} }
impl From<Rc<NamespacedKeyword>> for TypedValue { impl From<Rc<NamespacedKeyword>> for TypedValue {
fn from(value: Rc<NamespacedKeyword>) -> TypedValue { fn from(value: Rc<NamespacedKeyword>) -> TypedValue {
TypedValue::Keyword(value.clone()) TypedValue::Keyword(ValueRc::from_rc(value))
} }
} }
impl From<NamespacedKeyword> for TypedValue { impl From<NamespacedKeyword> for TypedValue {
fn from(value: NamespacedKeyword) -> TypedValue { fn from(value: NamespacedKeyword) -> TypedValue {
TypedValue::Keyword(Rc::new(value)) TypedValue::Keyword(ValueRc::new(value))
} }
} }
@ -442,7 +459,7 @@ impl TypedValue {
} }
} }
pub fn into_kw(self) -> Option<Rc<NamespacedKeyword>> { pub fn into_kw(self) -> Option<ValueRc<NamespacedKeyword>> {
match self { match self {
TypedValue::Keyword(v) => Some(v), TypedValue::Keyword(v) => Some(v),
_ => None, _ => None,
@ -484,7 +501,7 @@ impl TypedValue {
} }
} }
pub fn into_string(self) -> Option<Rc<String>> { pub fn into_string(self) -> Option<ValueRc<String>> {
match self { match self {
TypedValue::String(v) => Some(v), TypedValue::String(v) => Some(v),
_ => None, _ => None,
@ -521,7 +538,7 @@ impl Binding {
} }
} }
pub fn into_kw(self) -> Option<Rc<NamespacedKeyword>> { pub fn into_kw(self) -> Option<ValueRc<NamespacedKeyword>> {
match self { match self {
Binding::Scalar(TypedValue::Keyword(v)) => Some(v), Binding::Scalar(TypedValue::Keyword(v)) => Some(v),
_ => None, _ => None,
@ -563,7 +580,7 @@ impl Binding {
} }
} }
pub fn into_string(self) -> Option<Rc<String>> { pub fn into_string(self) -> Option<ValueRc<String>> {
match self { match self {
Binding::Scalar(TypedValue::String(v)) => Some(v), Binding::Scalar(TypedValue::String(v)) => Some(v),
_ => None, _ => None,

View file

@ -68,8 +68,6 @@ use std::iter::{
use std::mem; use std::mem;
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
use std::iter::Peekable; use std::iter::Peekable;
@ -85,6 +83,7 @@ use mentat_core::{
Schema, Schema,
TypedValue, TypedValue,
UpdateableCache, UpdateableCache,
ValueRc,
}; };
use mentat_core::util::{ use mentat_core::util::{
@ -190,7 +189,7 @@ pub type Aev = (Entid, Entid, TypedValue);
pub struct AevFactory { pub struct AevFactory {
// Our own simple string-interning system. // Our own simple string-interning system.
strings: HashSet<Rc<String>>, strings: HashSet<ValueRc<String>>,
} }
impl AevFactory { impl AevFactory {

View file

@ -19,7 +19,6 @@ use std::fmt::Display;
use std::iter::{once, repeat}; use std::iter::{once, repeat};
use std::ops::Range; use std::ops::Range;
use std::path::Path; use std::path::Path;
use std::rc::Rc;
use itertools; use itertools;
use itertools::Itertools; use itertools::Itertools;
@ -51,7 +50,9 @@ use mentat_core::{
TypedValue, TypedValue,
ToMicros, ToMicros,
ValueType, ValueType,
ValueRc,
}; };
use errors::{ErrorKind, Result, ResultExt}; use errors::{ErrorKind, Result, ResultExt};
use metadata; use metadata;
use schema::{ use schema::{
@ -872,7 +873,7 @@ impl MentatStoring for rusqlite::Connection {
let chunks: itertools::IntoChunks<_> = entities.into_iter().chunks(max_vars / bindings_per_statement); let chunks: itertools::IntoChunks<_> = entities.into_iter().chunks(max_vars / bindings_per_statement);
// From string to (searchid, value_type_tag). // From string to (searchid, value_type_tag).
let mut seen: HashMap<Rc<String>, (i64, i32)> = HashMap::with_capacity(entities.len()); let mut seen: HashMap<ValueRc<String>, (i64, i32)> = HashMap::with_capacity(entities.len());
// We'd like to flat_map here, but it's not obvious how to flat_map across Result. // We'd like to flat_map here, but it's not obvious how to flat_map across Result.
let results: Result<Vec<()>> = chunks.into_iter().map(|chunk| -> Result<()> { let results: Result<Vec<()>> = chunks.into_iter().map(|chunk| -> Result<()> {

View file

@ -25,6 +25,10 @@ use std::fmt::{
Formatter, Formatter,
}; };
use std::ops::{
Deref,
};
use mentat_core::{ use mentat_core::{
Attribute, Attribute,
Entid, Entid,
@ -97,13 +101,13 @@ pub use self::inputs::QueryInputs;
use Known; use Known;
// We do this a lot for errors. // We do this a lot for errors.
trait RcCloned<T> { trait Cloned<T> {
fn cloned(&self) -> T; fn cloned(&self) -> T;
} }
impl<T: Clone> RcCloned<T> for ::std::rc::Rc<T> { impl<T: Clone> Cloned<T> for ::mentat_core::ValueRc<T> {
fn cloned(&self) -> T { fn cloned(&self) -> T {
self.as_ref().clone() self.deref().clone()
} }
} }

View file

@ -24,7 +24,7 @@ use mentat_query::{
Variable, Variable,
}; };
use super::RcCloned; use super::Cloned;
use clauses::{ use clauses::{
ConjoiningClauses, ConjoiningClauses,

View file

@ -15,11 +15,10 @@ use std::fmt::{
Result, Result,
}; };
use std::rc::Rc;
use mentat_core::{ use mentat_core::{
Entid, Entid,
TypedValue, TypedValue,
ValueRc,
ValueType, ValueType,
ValueTypeSet, ValueTypeSet,
}; };
@ -709,7 +708,7 @@ pub enum EvolvedValuePlace {
Entid(Entid), Entid(Entid),
Value(TypedValue), Value(TypedValue),
EntidOrInteger(i64), EntidOrInteger(i64),
IdentOrKeyword(Rc<NamespacedKeyword>), IdentOrKeyword(ValueRc<NamespacedKeyword>),
} }
pub enum PlaceOrEmpty<T> { pub enum PlaceOrEmpty<T> {

View file

@ -55,7 +55,9 @@ pub use edn::{
}; };
use mentat_core::{ use mentat_core::{
FromRc,
TypedValue, TypedValue,
ValueRc,
ValueType, ValueType,
}; };
@ -205,7 +207,7 @@ pub enum NonIntegerConstant {
Boolean(bool), Boolean(bool),
BigInteger(BigInt), BigInteger(BigInt),
Float(OrderedFloat<f64>), Float(OrderedFloat<f64>),
Text(Rc<String>), Text(ValueRc<String>),
Instant(DateTime<Utc>), Instant(DateTime<Utc>),
Uuid(Uuid), Uuid(Uuid),
} }
@ -225,13 +227,13 @@ impl NonIntegerConstant {
impl<'a> From<&'a str> for NonIntegerConstant { impl<'a> From<&'a str> for NonIntegerConstant {
fn from(val: &'a str) -> NonIntegerConstant { fn from(val: &'a str) -> NonIntegerConstant {
NonIntegerConstant::Text(Rc::new(val.to_string())) NonIntegerConstant::Text(ValueRc::new(val.to_string()))
} }
} }
impl From<String> for NonIntegerConstant { impl From<String> for NonIntegerConstant {
fn from(val: String) -> NonIntegerConstant { fn from(val: String) -> NonIntegerConstant {
NonIntegerConstant::Text(Rc::new(val)) NonIntegerConstant::Text(ValueRc::new(val))
} }
} }
@ -324,18 +326,18 @@ pub enum PatternNonValuePlace {
Placeholder, Placeholder,
Variable(Variable), Variable(Variable),
Entid(i64), // Will always be +ve. See #190. Entid(i64), // Will always be +ve. See #190.
Ident(Rc<NamespacedKeyword>), Ident(ValueRc<NamespacedKeyword>),
} }
impl From<Rc<NamespacedKeyword>> for PatternNonValuePlace { impl From<Rc<NamespacedKeyword>> for PatternNonValuePlace {
fn from(value: Rc<NamespacedKeyword>) -> Self { fn from(value: Rc<NamespacedKeyword>) -> Self {
PatternNonValuePlace::Ident(value.clone()) PatternNonValuePlace::Ident(ValueRc::from_rc(value))
} }
} }
impl From<NamespacedKeyword> for PatternNonValuePlace { impl From<NamespacedKeyword> for PatternNonValuePlace {
fn from(value: NamespacedKeyword) -> Self { fn from(value: NamespacedKeyword) -> Self {
PatternNonValuePlace::Ident(Rc::new(value)) PatternNonValuePlace::Ident(ValueRc::new(value))
} }
} }
@ -387,7 +389,7 @@ impl FromValue<PatternNonValuePlace> for PatternNonValuePlace {
#[derive(Clone, Debug, Eq, PartialEq)] #[derive(Clone, Debug, Eq, PartialEq)]
pub enum IdentOrEntid { pub enum IdentOrEntid {
Ident(Rc<NamespacedKeyword>), Ident(NamespacedKeyword),
Entid(i64), Entid(i64),
} }
@ -399,19 +401,19 @@ pub enum PatternValuePlace {
Placeholder, Placeholder,
Variable(Variable), Variable(Variable),
EntidOrInteger(i64), EntidOrInteger(i64),
IdentOrKeyword(Rc<NamespacedKeyword>), IdentOrKeyword(ValueRc<NamespacedKeyword>),
Constant(NonIntegerConstant), Constant(NonIntegerConstant),
} }
impl From<Rc<NamespacedKeyword>> for PatternValuePlace { impl From<Rc<NamespacedKeyword>> for PatternValuePlace {
fn from(value: Rc<NamespacedKeyword>) -> Self { fn from(value: Rc<NamespacedKeyword>) -> Self {
PatternValuePlace::IdentOrKeyword(value.clone()) PatternValuePlace::IdentOrKeyword(ValueRc::from_rc(value))
} }
} }
impl From<NamespacedKeyword> for PatternValuePlace { impl From<NamespacedKeyword> for PatternValuePlace {
fn from(value: NamespacedKeyword) -> Self { fn from(value: NamespacedKeyword) -> Self {
PatternValuePlace::IdentOrKeyword(Rc::new(value)) PatternValuePlace::IdentOrKeyword(ValueRc::new(value))
} }
} }

View file

@ -24,6 +24,7 @@ use ordered_float::OrderedFloat;
use mentat_core::{ use mentat_core::{
ToMicros, ToMicros,
TypedValue, TypedValue,
ValueRc,
}; };
pub use rusqlite::types::Value; pub use rusqlite::types::Value;
@ -103,7 +104,7 @@ pub struct SQLiteQueryBuilder {
// Instead we track byte and String arguments separately, mapping them to their argument name, // Instead we track byte and String arguments separately, mapping them to their argument name,
// in order to dedupe. We'll add these to the regular argument vector later. // in order to dedupe. We'll add these to the regular argument vector later.
byte_args: HashMap<Vec<u8>, String>, // From value to argument name. byte_args: HashMap<Vec<u8>, String>, // From value to argument name.
string_args: HashMap<Rc<String>, String>, // From value to argument name. string_args: HashMap<ValueRc<String>, String>, // From value to argument name.
args: Vec<(String, Rc<rusqlite::types::Value>)>, // (arg, value). args: Vec<(String, Rc<rusqlite::types::Value>)>, // (arg, value).
} }