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::{
Entid,
FromRc,
KnownEntid,
TypedValue,
Binding,
ValueType,
ValueTypeTag,
ValueRc,
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.
///
/// 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>),
Instant(DateTime<Utc>), // Use `into()` to ensure truncation.
// TODO: &str throughout?
String(Rc<String>),
Keyword(Rc<NamespacedKeyword>),
String(ValueRc<String>),
Keyword(ValueRc<NamespacedKeyword>),
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)]
pub enum Binding {
Scalar(TypedValue),
Vec(Rc<Vec<Binding>>),
Map(Rc<StructuredMap>),
Vec(ValueRc<Vec<Binding>>),
Map(ValueRc<StructuredMap>),
}
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
/// using a different keyword only.
#[derive(Debug, Eq, PartialEq)]
pub struct StructuredMap(IndexMap<Rc<NamespacedKeyword>, Binding>);
pub struct StructuredMap(IndexMap<ValueRc<NamespacedKeyword>, Binding>);
impl Binding {
/// 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
/// 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.
pub fn typed_ns_keyword(ns: &str, name: &str) -> TypedValue {
NamespacedKeyword::new(ns, name).into()
}
/// 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.
pub fn typed_string(s: &str) -> TypedValue {
s.into()
@ -381,31 +386,43 @@ impl From<Uuid> for TypedValue {
impl<'a> From<&'a str> for 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 {
fn from(value: Rc<String>) -> TypedValue {
TypedValue::String(value.clone())
TypedValue::String(ValueRc::from_rc(value))
}
}
impl From<String> for 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 {
fn from(value: Rc<NamespacedKeyword>) -> TypedValue {
TypedValue::Keyword(value.clone())
TypedValue::Keyword(ValueRc::from_rc(value))
}
}
impl From<NamespacedKeyword> for 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 {
TypedValue::Keyword(v) => Some(v),
_ => 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 {
TypedValue::String(v) => Some(v),
_ => 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 {
Binding::Scalar(TypedValue::Keyword(v)) => Some(v),
_ => 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 {
Binding::Scalar(TypedValue::String(v)) => Some(v),
_ => None,

View file

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

View file

@ -19,7 +19,6 @@ use std::fmt::Display;
use std::iter::{once, repeat};
use std::ops::Range;
use std::path::Path;
use std::rc::Rc;
use itertools;
use itertools::Itertools;
@ -51,7 +50,9 @@ use mentat_core::{
TypedValue,
ToMicros,
ValueType,
ValueRc,
};
use errors::{ErrorKind, Result, ResultExt};
use metadata;
use schema::{
@ -872,7 +873,7 @@ impl MentatStoring for rusqlite::Connection {
let chunks: itertools::IntoChunks<_> = entities.into_iter().chunks(max_vars / bindings_per_statement);
// 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.
let results: Result<Vec<()>> = chunks.into_iter().map(|chunk| -> Result<()> {

View file

@ -25,6 +25,10 @@ use std::fmt::{
Formatter,
};
use std::ops::{
Deref,
};
use mentat_core::{
Attribute,
Entid,
@ -97,13 +101,13 @@ pub use self::inputs::QueryInputs;
use Known;
// We do this a lot for errors.
trait RcCloned<T> {
trait Cloned<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 {
self.as_ref().clone()
self.deref().clone()
}
}

View file

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

View file

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

View file

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