use super::*;
pub(in crate::transform) fn cast_value(
value: &JsonValue,
type_name: &str,
path: &str,
) -> Result<JsonValue, TransformError> {
match type_name {
"string" => Ok(JsonValue::String(value_to_string(value, path)?)),
"int" => cast_to_int(value, path),
"float" => cast_to_float(value, path),
"bool" => cast_to_bool(value, path),
_ => Err(TransformError::new(
TransformErrorKind::TypeCastFailed,
"type must be string|int|float|bool",
)
.with_path(path)),
}
}
fn cast_to_int(value: &JsonValue, path: &str) -> Result<JsonValue, TransformError> {
match value {
JsonValue::Number(n) => {
if let Some(i) = n.as_i64() {
Ok(JsonValue::Number(i.into()))
} else if let Some(f) = n.as_f64() {
if (f.fract()).abs() < f64::EPSILON {
Ok(JsonValue::Number((f as i64).into()))
} else {
Err(type_cast_error("int", path))
}
} else {
Err(type_cast_error("int", path))
}
}
JsonValue::String(s) => s
.parse::<i64>()
.map(|i| JsonValue::Number(i.into()))
.map_err(|_| type_cast_error("int", path)),
_ => Err(type_cast_error("int", path)),
}
}
fn cast_to_float(value: &JsonValue, path: &str) -> Result<JsonValue, TransformError> {
match value {
JsonValue::Number(n) => n
.as_f64()
.ok_or_else(|| type_cast_error("float", path))
.and_then(|f| {
serde_json::Number::from_f64(f)
.map(JsonValue::Number)
.ok_or_else(|| type_cast_error("float", path))
}),
JsonValue::String(s) => s
.parse::<f64>()
.map_err(|_| type_cast_error("float", path))
.and_then(|f| {
serde_json::Number::from_f64(f)
.map(JsonValue::Number)
.ok_or_else(|| type_cast_error("float", path))
}),
_ => Err(type_cast_error("float", path)),
}
}
fn cast_to_bool(value: &JsonValue, path: &str) -> Result<JsonValue, TransformError> {
match value {
JsonValue::Bool(b) => Ok(JsonValue::Bool(*b)),
JsonValue::String(s) => match s.to_lowercase().as_str() {
"true" => Ok(JsonValue::Bool(true)),
"false" => Ok(JsonValue::Bool(false)),
_ => Err(type_cast_error("bool", path)),
},
_ => Err(type_cast_error("bool", path)),
}
}
fn type_cast_error(type_name: &str, path: &str) -> TransformError {
TransformError::new(
TransformErrorKind::TypeCastFailed,
format!("failed to cast to {}", type_name),
)
.with_path(path)
}