Skip to content

Commit adb3798

Browse files
committed
map: represent valid map type states via enum
It's not possible for a map type to have value type defined, when key type is not defined. A representation of map type before this commit, would technically allow us to create such state. Introduced a `MapDataType` enum which represents valid states of map data type.
1 parent ee4c950 commit adb3798

File tree

5 files changed

+101
-85
lines changed

5 files changed

+101
-85
lines changed

scylla-rust-wrapper/src/cass_types.rs

Lines changed: 72 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,13 @@ impl Default for UDTDataType {
131131
}
132132
}
133133

134+
#[derive(Clone, Debug, PartialEq)]
135+
pub enum MapDataType {
136+
Untyped,
137+
Key(Arc<CassDataType>),
138+
KeyAndValue(Arc<CassDataType>, Arc<CassDataType>),
139+
}
140+
134141
#[derive(Clone, Debug, PartialEq)]
135142
pub enum CassDataType {
136143
Value(CassValueType),
@@ -146,10 +153,7 @@ pub enum CassDataType {
146153
frozen: bool,
147154
},
148155
Map {
149-
// None, None stands for untyped map.
150-
// Some, None stands for a map with an untyped value type.
151-
key_type: Option<Arc<CassDataType>>,
152-
val_type: Option<Arc<CassDataType>>,
156+
typ: MapDataType,
153157
frozen: bool,
154158
},
155159
// Empty vector stands for untyped tuple.
@@ -183,29 +187,22 @@ impl CassDataType {
183187
}
184188
_ => false,
185189
},
186-
CassDataType::Map {
187-
key_type: k,
188-
val_type: v,
189-
..
190-
} => match other {
191-
CassDataType::Map {
192-
key_type: k_other,
193-
val_type: v_other,
194-
..
195-
} => match ((k, v), (k_other, v_other)) {
190+
CassDataType::Map { typ: t, .. } => match other {
191+
CassDataType::Map { typ: t_other, .. } => match (t, t_other) {
196192
// See https://github.com/scylladb/cpp-driver/blob/master/src/data_type.hpp#L218
197193
// In cpp-driver the types are held in a vector.
198194
// The logic is following:
199195

200196
// If either of vectors is empty, skip the typecheck.
201-
((None, None), _) => true,
202-
(_, (None, None)) => true,
197+
(MapDataType::Untyped, _) => true,
198+
(_, MapDataType::Untyped) => true,
203199

204200
// Otherwise, the vectors should have equal length and we perform the typecheck for subtypes.
205-
((Some(k), None), (Some(k_other), None)) => k.typecheck_equals(k_other),
206-
((Some(k), Some(v)), (Some(k_other), Some(v_other))) => {
207-
k.typecheck_equals(k_other) && v.typecheck_equals(v_other)
208-
}
201+
(MapDataType::Key(k), MapDataType::Key(k_other)) => k.typecheck_equals(k_other),
202+
(
203+
MapDataType::KeyAndValue(k, v),
204+
MapDataType::KeyAndValue(k_other, v_other),
205+
) => k.typecheck_equals(k_other) && v.typecheck_equals(v_other),
209206
_ => false,
210207
},
211208
_ => false,
@@ -276,16 +273,18 @@ pub fn get_column_type_from_cql_type(
276273
frozen: *frozen,
277274
},
278275
CollectionType::Map(key, value) => CassDataType::Map {
279-
key_type: Some(Arc::new(get_column_type_from_cql_type(
280-
key,
281-
user_defined_types,
282-
keyspace_name,
283-
))),
284-
val_type: Some(Arc::new(get_column_type_from_cql_type(
285-
value,
286-
user_defined_types,
287-
keyspace_name,
288-
))),
276+
typ: MapDataType::KeyAndValue(
277+
Arc::new(get_column_type_from_cql_type(
278+
key,
279+
user_defined_types,
280+
keyspace_name,
281+
)),
282+
Arc::new(get_column_type_from_cql_type(
283+
value,
284+
user_defined_types,
285+
keyspace_name,
286+
)),
287+
),
289288
frozen: *frozen,
290289
},
291290
CollectionType::Set(set) => CassDataType::Set {
@@ -338,10 +337,19 @@ impl CassDataType {
338337
}
339338
}
340339
CassDataType::Map {
341-
key_type, val_type, ..
340+
typ: MapDataType::Untyped,
341+
..
342+
} => None,
343+
CassDataType::Map {
344+
typ: MapDataType::Key(k),
345+
..
346+
} if index == 0 => Some(k),
347+
CassDataType::Map {
348+
typ: MapDataType::KeyAndValue(k, v),
349+
..
342350
} => match index {
343-
0 => key_type.as_ref(),
344-
1 => val_type.as_ref(),
351+
0 => Some(k),
352+
1 => Some(v),
345353
_ => None,
346354
},
347355
CassDataType::Tuple(v) => v.get(index),
@@ -359,17 +367,28 @@ impl CassDataType {
359367
}
360368
},
361369
CassDataType::Map {
362-
key_type, val_type, ..
370+
typ: MapDataType::KeyAndValue(_, _),
371+
..
372+
} => Err(CassError::CASS_ERROR_LIB_BAD_PARAMS),
373+
CassDataType::Map {
374+
typ: MapDataType::Key(k),
375+
frozen,
363376
} => {
364-
if key_type.is_some() && val_type.is_some() {
365-
Err(CassError::CASS_ERROR_LIB_BAD_PARAMS)
366-
} else if key_type.is_none() {
367-
*key_type = Some(sub_type);
368-
Ok(())
369-
} else {
370-
*val_type = Some(sub_type);
371-
Ok(())
372-
}
377+
*self = CassDataType::Map {
378+
typ: MapDataType::KeyAndValue(k.clone(), sub_type),
379+
frozen: *frozen,
380+
};
381+
Ok(())
382+
}
383+
CassDataType::Map {
384+
typ: MapDataType::Untyped,
385+
frozen,
386+
} => {
387+
*self = CassDataType::Map {
388+
typ: MapDataType::Key(sub_type),
389+
frozen: *frozen,
390+
};
391+
Ok(())
373392
}
374393
CassDataType::Tuple(types) => {
375394
types.push(sub_type);
@@ -421,8 +440,10 @@ pub fn get_column_type(column_type: &ColumnType) -> CassDataType {
421440
frozen: false,
422441
},
423442
ColumnType::Map(key, value) => CassDataType::Map {
424-
key_type: Some(Arc::new(get_column_type(key.as_ref()))),
425-
val_type: Some(Arc::new(get_column_type(value.as_ref()))),
443+
typ: MapDataType::KeyAndValue(
444+
Arc::new(get_column_type(key.as_ref())),
445+
Arc::new(get_column_type(value.as_ref())),
446+
),
426447
frozen: false,
427448
},
428449
ColumnType::Set(boxed_type) => CassDataType::Set {
@@ -473,8 +494,7 @@ pub unsafe extern "C" fn cass_data_type_new(value_type: CassValueType) -> *const
473494
},
474495
CassValueType::CASS_VALUE_TYPE_TUPLE => CassDataType::Tuple(Vec::new()),
475496
CassValueType::CASS_VALUE_TYPE_MAP => CassDataType::Map {
476-
key_type: None,
477-
val_type: None,
497+
typ: MapDataType::Untyped,
478498
frozen: false,
479499
},
480500
CassValueType::CASS_VALUE_TYPE_UDT => CassDataType::UDT(UDTDataType::new()),
@@ -671,9 +691,11 @@ pub unsafe extern "C" fn cass_data_type_sub_type_count(data_type: *const CassDat
671691
CassDataType::Value(..) => 0,
672692
CassDataType::UDT(udt_data_type) => udt_data_type.field_types.len() as size_t,
673693
CassDataType::List { typ, .. } | CassDataType::Set { typ, .. } => typ.is_some() as size_t,
674-
CassDataType::Map {
675-
key_type, val_type, ..
676-
} => key_type.is_some() as size_t + val_type.is_some() as size_t,
694+
CassDataType::Map { typ, .. } => match typ {
695+
MapDataType::Untyped => 0,
696+
MapDataType::Key(_) => 1,
697+
MapDataType::KeyAndValue(_, _) => 2,
698+
},
677699
CassDataType::Tuple(v) => v.len() as size_t,
678700
CassDataType::Custom(..) => 0,
679701
}

scylla-rust-wrapper/src/collection.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::cass_error::CassError;
2-
use crate::cass_types::CassDataType;
2+
use crate::cass_types::{CassDataType, MapDataType};
33
use crate::types::*;
44
use crate::value::CassCqlValue;
55
use crate::{argconv::*, value};
@@ -18,8 +18,7 @@ static UNTYPED_SET_TYPE: CassDataType = CassDataType::Set {
1818
frozen: false,
1919
};
2020
static UNTYPED_MAP_TYPE: CassDataType = CassDataType::Map {
21-
key_type: None,
22-
val_type: None,
21+
typ: MapDataType::Untyped,
2322
frozen: false,
2423
};
2524

@@ -47,19 +46,17 @@ impl CassCollection {
4746
}
4847
}
4948
}
49+
5050
CassDataType::Map {
51-
key_type: k_typ,
52-
val_type: v_typ,
51+
// Only do the typecheck if both map types are present.
52+
typ: MapDataType::KeyAndValue(k_typ, v_typ),
5353
..
5454
} => {
55-
// Only do the typecheck if both map types are present.
56-
if let (Some(k_typ), Some(v_typ)) = (k_typ, v_typ) {
57-
if index % 2 == 0 && !value::is_type_compatible(value, k_typ) {
58-
return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
59-
}
60-
if index % 2 != 0 && !value::is_type_compatible(value, v_typ) {
61-
return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
62-
}
55+
if index % 2 == 0 && !value::is_type_compatible(value, k_typ) {
56+
return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
57+
}
58+
if index % 2 != 0 && !value::is_type_compatible(value, v_typ) {
59+
return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE;
6360
}
6461
}
6562
_ => return CassError::CASS_ERROR_LIB_INVALID_VALUE_TYPE,
@@ -210,7 +207,7 @@ mod tests {
210207

211208
use crate::{
212209
cass_error::CassError,
213-
cass_types::{CassDataType, CassValueType},
210+
cass_types::{CassDataType, CassValueType, MapDataType},
214211
collection::{
215212
cass_collection_append_double, cass_collection_append_float, cass_collection_free,
216213
},
@@ -251,12 +248,12 @@ mod tests {
251248
// typed map
252249
{
253250
let dt = Arc::new(CassDataType::Map {
254-
key_type: Some(Arc::new(CassDataType::Value(
255-
CassValueType::CASS_VALUE_TYPE_BOOLEAN,
256-
))),
257-
val_type: Some(Arc::new(CassDataType::Value(
258-
CassValueType::CASS_VALUE_TYPE_SMALL_INT,
259-
))),
251+
typ: MapDataType::KeyAndValue(
252+
Arc::new(CassDataType::Value(CassValueType::CASS_VALUE_TYPE_BOOLEAN)),
253+
Arc::new(CassDataType::Value(
254+
CassValueType::CASS_VALUE_TYPE_SMALL_INT,
255+
)),
256+
),
260257
frozen: false,
261258
});
262259
let dt_ptr = Arc::into_raw(dt);

scylla-rust-wrapper/src/query_result.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::argconv::*;
22
use crate::cass_error::CassError;
3-
use crate::cass_types::{cass_data_type_type, CassDataType, CassValueType};
3+
use crate::cass_types::{cass_data_type_type, CassDataType, CassValueType, MapDataType};
44
use crate::inet::CassInet;
55
use crate::metadata::{
66
CassColumnMeta, CassKeyspaceMeta, CassMaterializedViewMeta, CassSchemaMeta, CassTableMeta,
@@ -1239,7 +1239,7 @@ pub unsafe extern "C" fn cass_value_primary_sub_type(
12391239
} => list.get_value_type(),
12401240
CassDataType::Set { typ: Some(set), .. } => set.get_value_type(),
12411241
CassDataType::Map {
1242-
key_type: Some(key),
1242+
typ: MapDataType::Key(key) | MapDataType::KeyAndValue(key, _),
12431243
..
12441244
} => key.get_value_type(),
12451245
_ => CassValueType::CASS_VALUE_TYPE_UNKNOWN,
@@ -1254,7 +1254,7 @@ pub unsafe extern "C" fn cass_value_secondary_sub_type(
12541254

12551255
match val.value_type.as_ref() {
12561256
CassDataType::Map {
1257-
val_type: Some(value),
1257+
typ: MapDataType::KeyAndValue(_, value),
12581258
..
12591259
} => value.get_value_type(),
12601260
_ => CassValueType::CASS_VALUE_TYPE_UNKNOWN,

scylla-rust-wrapper/src/session.rs

Lines changed: 4 additions & 5 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::{get_column_type, CassDataType, UDTDataType};
4+
use crate::cass_types::{get_column_type, CassDataType, MapDataType, UDTDataType};
55
use crate::cluster::build_session_builder;
66
use crate::cluster::CassCluster;
77
use crate::exec_profile::{CassExecProfile, ExecProfileName, PerStatementExecProfile};
@@ -388,17 +388,16 @@ fn get_column_value(column: CqlValue, column_type: &Arc<CassDataType>) -> Value
388388
(
389389
CqlValue::Map(map),
390390
CassDataType::Map {
391-
key_type: Some(key_typ),
392-
val_type: Some(value_type),
391+
typ: MapDataType::KeyAndValue(key_type, value_type),
393392
..
394393
},
395394
) => CollectionValue(Collection::Map(
396395
map.into_iter()
397396
.map(|(key, val)| {
398397
(
399398
CassValue {
400-
value_type: key_typ.clone(),
401-
value: Some(get_column_value(key, key_typ)),
399+
value_type: key_type.clone(),
400+
value: Some(get_column_value(key, key_type)),
402401
},
403402
CassValue {
404403
value_type: value_type.clone(),

scylla-rust-wrapper/src/value.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ mod tests {
399399
use scylla::frame::value::{CqlDate, CqlDecimal, CqlDuration};
400400

401401
use crate::{
402-
cass_types::{CassDataType, CassValueType, UDTDataType},
402+
cass_types::{CassDataType, CassValueType, MapDataType, UDTDataType},
403403
value::{is_type_compatible, CassCqlValue},
404404
};
405405

@@ -778,18 +778,16 @@ mod tests {
778778
});
779779

780780
let data_type_untyped_map = Arc::new(CassDataType::Map {
781-
key_type: None,
782-
val_type: None,
781+
typ: MapDataType::Untyped,
783782
frozen: false,
784783
});
785784
let data_type_typed_key_float_map = Arc::new(CassDataType::Map {
786-
key_type: Some(data_type_float.clone()),
787-
val_type: None,
785+
typ: MapDataType::Key(data_type_float.clone()),
786+
788787
frozen: false,
789788
});
790789
let data_type_float_int_map = Arc::new(CassDataType::Map {
791-
key_type: Some(data_type_float.clone()),
792-
val_type: Some(data_type_int.clone()),
790+
typ: MapDataType::KeyAndValue(data_type_float.clone(), data_type_int.clone()),
793791
frozen: false,
794792
});
795793

0 commit comments

Comments
 (0)