Skip to content

Commit 50f4322

Browse files
Lorak-mmkmuzarski
authored andcommitted
Put content of CassDataType into UnsafeCell
Previously `CassDataType` was just an enum, held inside `Arc`. User was given a pointer to `CassDataType` using `Arc::as_ptr` or `Arc::into_ptr`. There are however some functions that mutate the data - and they were given the very same pointers. Current code was most likely sound - but I'm not completely sure, Rust reference is very confusing in this aspect. It was however very confusing - when a programmer reads or writes a function that that *mut CassDataType it is not obivious that this data lies inside Arc and so has shared ownership. To make this more explicit this commit puts `CassDataType` inside UnsafeCell. Now each access needs to use `.get_unchecked()` and `.get_mut_unchecked()` methods and an unsafe block / function, so it will be easier to spot aliasing ^ mutability problems in the future. In the future we can use `Arc::get_mut_unchecked()` for this purpose, but it's not yet stabilised.
1 parent f1ed076 commit 50f4322

File tree

7 files changed

+433
-314
lines changed

7 files changed

+433
-314
lines changed

scylla-rust-wrapper/src/cass_types.rs

Lines changed: 208 additions & 146 deletions
Large diffs are not rendered by default.

scylla-rust-wrapper/src/collection.rs

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
use crate::cass_collection_types::CassCollectionType;
22
use crate::cass_error::CassError;
3-
use crate::cass_types::{CassDataType, MapDataType};
3+
use crate::cass_types::{CassDataType, CassDataTypeInner, MapDataType};
44
use crate::types::*;
55
use crate::value::CassCqlValue;
66
use crate::{argconv::*, value};
77
use std::convert::TryFrom;
88
use std::sync::Arc;
99

1010
// These constants help us to save an allocation in case user calls `cass_collection_new` (untyped collection).
11-
static UNTYPED_LIST_TYPE: CassDataType = CassDataType::List {
11+
static UNTYPED_LIST_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::List {
1212
typ: None,
1313
frozen: false,
14-
};
15-
static UNTYPED_SET_TYPE: CassDataType = CassDataType::Set {
14+
});
15+
static UNTYPED_SET_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::Set {
1616
typ: None,
1717
frozen: false,
18-
};
19-
static UNTYPED_MAP_TYPE: CassDataType = CassDataType::Map {
18+
});
19+
static UNTYPED_MAP_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::Map {
2020
typ: MapDataType::Untyped,
2121
frozen: false,
22-
};
22+
});
2323

2424
#[derive(Clone)]
2525
pub struct CassCollection {
@@ -35,18 +35,22 @@ impl CassCollection {
3535
let index = self.items.len();
3636

3737
// Do validation only if it's a typed collection.
38-
if let Some(data_type) = &self.data_type {
39-
match data_type.as_ref() {
40-
CassDataType::List { typ: subtype, .. }
41-
| CassDataType::Set { typ: subtype, .. } => {
38+
if let Some(data_type) = &self
39+
.data_type
40+
.as_ref()
41+
.map(|dt| unsafe { dt.get_unchecked() })
42+
{
43+
match data_type {
44+
CassDataTypeInner::List { typ: subtype, .. }
45+
| CassDataTypeInner::Set { typ: subtype, .. } => {
4246
if let Some(subtype) = subtype {
4347
if !value::is_type_compatible(value, subtype) {
4448
return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
4549
}
4650
}
4751
}
4852

49-
CassDataType::Map { typ, .. } => {
53+
CassDataTypeInner::Map { typ, .. } => {
5054
// Cpp-driver does the typecheck only if both map types are present...
5155
// However, we decided not to mimic this behaviour (which is probably a bug).
5256
// We will do the typecheck if just the key type is defined as well (half-typed maps).
@@ -146,12 +150,16 @@ unsafe extern "C" fn cass_collection_new_from_data_type(
146150
item_count: size_t,
147151
) -> *mut CassCollection {
148152
let data_type = clone_arced(data_type);
149-
let (capacity, collection_type) = match data_type.as_ref() {
150-
CassDataType::List { .. } => (item_count, CassCollectionType::CASS_COLLECTION_TYPE_LIST),
151-
CassDataType::Set { .. } => (item_count, CassCollectionType::CASS_COLLECTION_TYPE_SET),
153+
let (capacity, collection_type) = match data_type.get_unchecked() {
154+
CassDataTypeInner::List { .. } => {
155+
(item_count, CassCollectionType::CASS_COLLECTION_TYPE_LIST)
156+
}
157+
CassDataTypeInner::Set { .. } => (item_count, CassCollectionType::CASS_COLLECTION_TYPE_SET),
152158
// Maps consist of a key and a value, so twice
153159
// the number of CassCqlValue will be stored.
154-
CassDataType::Map { .. } => (item_count * 2, CassCollectionType::CASS_COLLECTION_TYPE_MAP),
160+
CassDataTypeInner::Map { .. } => {
161+
(item_count * 2, CassCollectionType::CASS_COLLECTION_TYPE_MAP)
162+
}
155163
_ => return std::ptr::null_mut(),
156164
};
157165
let capacity = capacity as usize;
@@ -216,7 +224,7 @@ mod tests {
216224

217225
use crate::{
218226
cass_error::CassError,
219-
cass_types::{CassDataType, CassValueType, MapDataType},
227+
cass_types::{CassDataType, CassDataTypeInner, CassValueType, MapDataType},
220228
collection::{
221229
cass_collection_append_double, cass_collection_append_float, cass_collection_free,
222230
},
@@ -256,7 +264,7 @@ mod tests {
256264

257265
// untyped map (via cass_collection_new_from_data_type - collection's type is Some(untyped_map)).
258266
{
259-
let dt = Arc::new(CassDataType::Map {
267+
let dt = CassDataType::new_arced(CassDataTypeInner::Map {
260268
typ: MapDataType::Untyped,
261269
frozen: false,
262270
});
@@ -285,8 +293,8 @@ mod tests {
285293

286294
// half-typed map (key-only)
287295
{
288-
let dt = Arc::new(CassDataType::Map {
289-
typ: MapDataType::Key(Arc::new(CassDataType::Value(
296+
let dt = CassDataType::new_arced(CassDataTypeInner::Map {
297+
typ: MapDataType::Key(CassDataType::new_arced(CassDataTypeInner::Value(
290298
CassValueType::CASS_VALUE_TYPE_BOOLEAN,
291299
))),
292300
frozen: false,
@@ -324,10 +332,12 @@ mod tests {
324332

325333
// typed map
326334
{
327-
let dt = Arc::new(CassDataType::Map {
335+
let dt = CassDataType::new_arced(CassDataTypeInner::Map {
328336
typ: MapDataType::KeyAndValue(
329-
Arc::new(CassDataType::Value(CassValueType::CASS_VALUE_TYPE_BOOLEAN)),
330-
Arc::new(CassDataType::Value(
337+
CassDataType::new_arced(CassDataTypeInner::Value(
338+
CassValueType::CASS_VALUE_TYPE_BOOLEAN,
339+
)),
340+
CassDataType::new_arced(CassDataTypeInner::Value(
331341
CassValueType::CASS_VALUE_TYPE_SMALL_INT,
332342
)),
333343
),
@@ -383,7 +393,7 @@ mod tests {
383393

384394
// untyped set (via cass_collection_new_from_data_type, collection's type is Some(untyped_set))
385395
{
386-
let dt = Arc::new(CassDataType::Set {
396+
let dt = CassDataType::new_arced(CassDataTypeInner::Set {
387397
typ: None,
388398
frozen: false,
389399
});
@@ -404,8 +414,8 @@ mod tests {
404414

405415
// typed set
406416
{
407-
let dt = Arc::new(CassDataType::Set {
408-
typ: Some(Arc::new(CassDataType::Value(
417+
let dt = CassDataType::new_arced(CassDataTypeInner::Set {
418+
typ: Some(CassDataType::new_arced(CassDataTypeInner::Value(
409419
CassValueType::CASS_VALUE_TYPE_BOOLEAN,
410420
))),
411421
frozen: false,
@@ -443,7 +453,7 @@ mod tests {
443453

444454
// untyped list (via cass_collection_new_from_data_type, collection's type is Some(untyped_list))
445455
{
446-
let dt = Arc::new(CassDataType::Set {
456+
let dt = CassDataType::new_arced(CassDataTypeInner::Set {
447457
typ: None,
448458
frozen: false,
449459
});
@@ -464,8 +474,8 @@ mod tests {
464474

465475
// typed list
466476
{
467-
let dt = Arc::new(CassDataType::Set {
468-
typ: Some(Arc::new(CassDataType::Value(
477+
let dt = CassDataType::new_arced(CassDataTypeInner::Set {
478+
typ: Some(CassDataType::new_arced(CassDataTypeInner::Value(
469479
CassValueType::CASS_VALUE_TYPE_BOOLEAN,
470480
))),
471481
frozen: false,

scylla-rust-wrapper/src/query_result.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use crate::argconv::*;
22
use crate::cass_error::CassError;
33
use crate::cass_types::{
4-
cass_data_type_type, get_column_type, CassColumnSpec, CassDataType, CassValueType, MapDataType,
4+
cass_data_type_type, get_column_type, CassColumnSpec, CassDataType, CassDataTypeInner,
5+
CassValueType, MapDataType,
56
};
67
use crate::inet::CassInet;
78
use crate::metadata::{
@@ -195,10 +196,10 @@ fn create_cass_row_columns(row: Row, metadata: &Arc<CassResultMetadata>) -> Vec<
195196
}
196197

197198
fn get_column_value(column: CqlValue, column_type: &Arc<CassDataType>) -> Value {
198-
match (column, column_type.as_ref()) {
199+
match (column, unsafe { column_type.get_unchecked() }) {
199200
(
200201
CqlValue::List(list),
201-
CassDataType::List {
202+
CassDataTypeInner::List {
202203
typ: Some(list_type),
203204
..
204205
},
@@ -212,7 +213,7 @@ fn get_column_value(column: CqlValue, column_type: &Arc<CassDataType>) -> Value
212213
)),
213214
(
214215
CqlValue::Map(map),
215-
CassDataType::Map {
216+
CassDataTypeInner::Map {
216217
typ: MapDataType::KeyAndValue(key_type, value_type),
217218
..
218219
},
@@ -234,7 +235,7 @@ fn get_column_value(column: CqlValue, column_type: &Arc<CassDataType>) -> Value
234235
)),
235236
(
236237
CqlValue::Set(set),
237-
CassDataType::Set {
238+
CassDataTypeInner::Set {
238239
typ: Some(set_type),
239240
..
240241
},
@@ -252,7 +253,7 @@ fn get_column_value(column: CqlValue, column_type: &Arc<CassDataType>) -> Value
252253
type_name,
253254
fields,
254255
},
255-
CassDataType::UDT(udt_type),
256+
CassDataTypeInner::UDT(udt_type),
256257
) => CollectionValue(Collection::UserDefinedType {
257258
keyspace,
258259
type_name,
@@ -274,7 +275,7 @@ fn get_column_value(column: CqlValue, column_type: &Arc<CassDataType>) -> Value
274275
})
275276
.collect(),
276277
}),
277-
(CqlValue::Tuple(tuple), CassDataType::Tuple(tuple_types)) => {
278+
(CqlValue::Tuple(tuple), CassDataTypeInner::Tuple(tuple_types)) => {
278279
CollectionValue(Collection::Tuple(
279280
tuple
280281
.into_iter()
@@ -1472,7 +1473,7 @@ pub unsafe extern "C" fn cass_value_is_collection(value: *const CassValue) -> ca
14721473
let val = ptr_to_ref(value);
14731474

14741475
matches!(
1475-
val.value_type.get_value_type(),
1476+
val.value_type.get_unchecked().get_value_type(),
14761477
CassValueType::CASS_VALUE_TYPE_LIST
14771478
| CassValueType::CASS_VALUE_TYPE_SET
14781479
| CassValueType::CASS_VALUE_TYPE_MAP
@@ -1483,7 +1484,8 @@ pub unsafe extern "C" fn cass_value_is_collection(value: *const CassValue) -> ca
14831484
pub unsafe extern "C" fn cass_value_is_duration(value: *const CassValue) -> cass_bool_t {
14841485
let val = ptr_to_ref(value);
14851486

1486-
(val.value_type.get_value_type() == CassValueType::CASS_VALUE_TYPE_DURATION) as cass_bool_t
1487+
(val.value_type.get_unchecked().get_value_type() == CassValueType::CASS_VALUE_TYPE_DURATION)
1488+
as cass_bool_t
14871489
}
14881490

14891491
#[no_mangle]
@@ -1508,15 +1510,15 @@ pub unsafe extern "C" fn cass_value_primary_sub_type(
15081510
) -> CassValueType {
15091511
let val = ptr_to_ref(collection);
15101512

1511-
match val.value_type.as_ref() {
1512-
CassDataType::List {
1513+
match val.value_type.get_unchecked() {
1514+
CassDataTypeInner::List {
15131515
typ: Some(list), ..
1514-
} => list.get_value_type(),
1515-
CassDataType::Set { typ: Some(set), .. } => set.get_value_type(),
1516-
CassDataType::Map {
1516+
} => list.get_unchecked().get_value_type(),
1517+
CassDataTypeInner::Set { typ: Some(set), .. } => set.get_unchecked().get_value_type(),
1518+
CassDataTypeInner::Map {
15171519
typ: MapDataType::Key(key) | MapDataType::KeyAndValue(key, _),
15181520
..
1519-
} => key.get_value_type(),
1521+
} => key.get_unchecked().get_value_type(),
15201522
_ => CassValueType::CASS_VALUE_TYPE_UNKNOWN,
15211523
}
15221524
}
@@ -1527,11 +1529,11 @@ pub unsafe extern "C" fn cass_value_secondary_sub_type(
15271529
) -> CassValueType {
15281530
let val = ptr_to_ref(collection);
15291531

1530-
match val.value_type.as_ref() {
1531-
CassDataType::Map {
1532+
match val.value_type.get_unchecked() {
1533+
CassDataTypeInner::Map {
15321534
typ: MapDataType::KeyAndValue(_, value),
15331535
..
1534-
} => value.get_value_type(),
1536+
} => value.get_unchecked().get_value_type(),
15351537
_ => CassValueType::CASS_VALUE_TYPE_UNKNOWN,
15361538
}
15371539
}
@@ -1614,7 +1616,7 @@ mod tests {
16141616

16151617
use crate::{
16161618
cass_error::CassError,
1617-
cass_types::{CassDataType, CassValueType},
1619+
cass_types::{CassDataType, CassDataTypeInner, CassValueType},
16181620
query_result::{
16191621
cass_result_column_data_type, cass_result_column_name, cass_result_first_row,
16201622
ptr_to_cstr_n, ptr_to_ref, size_t,
@@ -1723,22 +1725,26 @@ mod tests {
17231725
{
17241726
let first_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 0));
17251727
assert_eq!(
1726-
&CassDataType::Value(CassValueType::CASS_VALUE_TYPE_BIGINT),
1728+
&CassDataType::new(CassDataTypeInner::Value(
1729+
CassValueType::CASS_VALUE_TYPE_BIGINT
1730+
)),
17271731
first_col_data_type
17281732
);
17291733
let second_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 1));
17301734
assert_eq!(
1731-
&CassDataType::Value(CassValueType::CASS_VALUE_TYPE_VARINT),
1735+
&CassDataType::new(CassDataTypeInner::Value(
1736+
CassValueType::CASS_VALUE_TYPE_VARINT
1737+
)),
17321738
second_col_data_type
17331739
);
17341740
let third_col_data_type = ptr_to_ref(cass_result_column_data_type(result_ptr, 2));
17351741
assert_eq!(
1736-
&CassDataType::List {
1737-
typ: Some(Arc::new(CassDataType::Value(
1742+
&CassDataType::new(CassDataTypeInner::List {
1743+
typ: Some(CassDataType::new_arced(CassDataTypeInner::Value(
17381744
CassValueType::CASS_VALUE_TYPE_DOUBLE
17391745
))),
17401746
frozen: false
1741-
},
1747+
}),
17421748
third_col_data_type
17431749
);
17441750
let out_of_bound_col_data_type = cass_result_column_data_type(result_ptr, 555);

scylla-rust-wrapper/src/session.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::argconv::*;
22
use crate::batch::CassBatch;
33
use crate::cass_error::*;
4-
use crate::cass_types::{CassDataType, UDTDataType};
4+
use crate::cass_types::{CassDataType, CassDataTypeInner, UDTDataType};
55
use crate::cluster::build_session_builder;
66
use crate::cluster::CassCluster;
77
use crate::exec_profile::{CassExecProfile, ExecProfileName, PerStatementExecProfile};
@@ -509,7 +509,7 @@ pub unsafe extern "C" fn cass_session_get_schema_meta(
509509
for udt_name in keyspace.user_defined_types.keys() {
510510
user_defined_type_data_type.insert(
511511
udt_name.clone(),
512-
Arc::new(CassDataType::UDT(UDTDataType::create_with_params(
512+
CassDataType::new_arced(CassDataTypeInner::UDT(UDTDataType::create_with_params(
513513
&keyspace.user_defined_types,
514514
keyspace_name,
515515
udt_name,

scylla-rust-wrapper/src/tuple.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::argconv::*;
22
use crate::cass_error::CassError;
33
use crate::cass_types::CassDataType;
4+
use crate::cass_types::CassDataTypeInner;
45
use crate::types::*;
56
use crate::value;
67
use crate::value::CassCqlValue;
78
use std::sync::Arc;
89

9-
static UNTYPED_TUPLE_TYPE: CassDataType = CassDataType::Tuple(Vec::new());
10+
static UNTYPED_TUPLE_TYPE: CassDataType = CassDataType::new(CassDataTypeInner::Tuple(Vec::new()));
1011

1112
#[derive(Clone)]
1213
pub struct CassTuple {
@@ -17,8 +18,8 @@ pub struct CassTuple {
1718
impl CassTuple {
1819
fn get_types(&self) -> Option<&Vec<Arc<CassDataType>>> {
1920
match &self.data_type {
20-
Some(t) => match &**t {
21-
CassDataType::Tuple(v) => Some(v),
21+
Some(t) => match unsafe { t.as_ref().get_unchecked() } {
22+
CassDataTypeInner::Tuple(v) => Some(v),
2223
_ => unreachable!(),
2324
},
2425
None => None,
@@ -70,8 +71,8 @@ unsafe extern "C" fn cass_tuple_new_from_data_type(
7071
data_type: *const CassDataType,
7172
) -> *mut CassTuple {
7273
let data_type = clone_arced(data_type);
73-
let item_count = match &*data_type {
74-
CassDataType::Tuple(v) => v.len(),
74+
let item_count = match data_type.get_unchecked() {
75+
CassDataTypeInner::Tuple(v) => v.len(),
7576
_ => return std::ptr::null_mut(),
7677
};
7778
Box::into_raw(Box::new(CassTuple {

0 commit comments

Comments
 (0)