tokio-rs / prost

PROST! a Protocol Buffers implementation for the Rust Language
Apache License 2.0
3.74k stars 484 forks source link

Value, Datetime serde support #590

Open lizelive opened 2 years ago

lizelive commented 2 years ago
fn proto_value_to_serde_value(value: prost_types::Value) -> serde_value::Value {
    match value.kind {
        Some(prost_types::value::Kind::NullValue(_)) => serde_value::Value::Unit,
        Some(prost_types::value::Kind::NumberValue(x)) => serde_value::Value::F64(x),
        Some(prost_types::value::Kind::StringValue(x)) => serde_value::Value::String(x),
        Some(prost_types::value::Kind::BoolValue(x)) => serde_value::Value::Bool(x),
        Some(prost_types::value::Kind::StructValue(x)) => serde_value::Value::Map(
            x.fields
                .into_iter()
                .map(|(k, v)| (serde_value::Value::String(k), proto_value_to_serde_value(v)))
                .collect(),
        ),
        Some(prost_types::value::Kind::ListValue(x)) => serde_value::Value::Seq(
            x.values
                .into_iter()
                .map(proto_value_to_serde_value)
                .collect(),
        ),
        None => todo!("not sure if this happens"),
        //_ => todo!("did not see that coming"),
    }
}

#[derive(thiserror::Error, Debug)]
pub enum ValueCastError {
    #[error("invalid key")]
    InvalidKey,
    #[error("no matching type")]
    NoMatchingType,
}
fn serde_value_to_proto_value(value: serde_value::Value) -> prost_types::Value {
    match value {
        serde_value::Value::Bool(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::BoolValue(x)),
        },
        serde_value::Value::U8(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::U16(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::U32(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::U64(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x as f64)),
        },
        serde_value::Value::I64(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x as f64)),
        },
        serde_value::Value::I8(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::I16(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::I32(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::F32(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::F64(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
        },
        serde_value::Value::Char(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::StringValue(x.into())),
        },
        serde_value::Value::String(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::StringValue(x.into())),
        },
        serde_value::Value::Unit => prost_types::Value {
            kind: Some(prost_types::value::Kind::NullValue(0)),
        },
        serde_value::Value::Option(x) => {
            x.map(|x| serde_value_to_proto_value(*x))
                .unwrap_or(prost_types::Value {
                    kind: Some(prost_types::value::Kind::NullValue(0)),
                })
        }
        serde_value::Value::Newtype(x) => serde_value_to_proto_value(*x),
        serde_value::Value::Seq(x) => {
            let values = x.into_iter().map(serde_value_to_proto_value).collect();
            prost_types::Value {
                kind: Some(prost_types::value::Kind::ListValue(
                    prost_types::ListValue { values },
                )),
            }
        }
        serde_value::Value::Map(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::StructValue(prost_types::Struct {
                fields: x
                    .into_iter()
                    .map(|(k, v)| match (k, serde_value_to_proto_value(v)) {
                        (serde_value::Value::String(k), v) => (k, v),
                        _ => panic!("InvalidKey"),
                    })
                    .collect(),
            })),
        },
        serde_value::Value::Bytes(x) => prost_types::Value {
            kind: Some(prost_types::value::Kind::ListValue(
                prost_types::ListValue {
                    values: x
                        .into_iter()
                        .map(|x| prost_types::Value {
                            kind: Some(prost_types::value::Kind::NumberValue(x.into())),
                        })
                        .collect(),
                },
            )),
        },
    }
}

const NANOS_PER_SECOND: i64 = 1000000;

fn chrono_to_prost_timestamp(timestamp: chrono::DateTime<chrono::Utc>) -> prost_types::Timestamp {
    let nanos = timestamp.timestamp_nanos();
    let seconds = nanos / NANOS_PER_SECOND;
    let nanos = (nanos % NANOS_PER_SECOND) as i32;
    prost_types::Timestamp { nanos, seconds }
}

fn prost_timestamp_to_chrono(timestamp: prost_types::Timestamp) -> chrono::DateTime<chrono::Utc> {
    let nanos = timestamp.seconds * NANOS_PER_SECOND + timestamp.nanos as i64;
    chrono::Utc.timestamp_nanos(nanos)
}

serde_with::serde_conv!(
    ProtoDatetimeAsChrono,
    Option<prost_types::Timestamp>,
    |value: &Option<prost_types::Timestamp>| { value.clone().map(prost_timestamp_to_chrono) },
    |value: Option<chrono::DateTime<chrono::Utc>>| -> Result<_, std::convert::Infallible> {
        Ok(value.map(chrono_to_prost_timestamp))
    }
);

serde_with::serde_conv!(
    ProtoValueAsSerdeValue,
    Option<prost_types::Value>,
    |value: &Option<prost_types::Value>| { value.clone().map(proto_value_to_serde_value) },
    |value: Option<serde_value::Value>| -> Result<_, std::convert::Infallible> {
        Ok(value.map(serde_value_to_proto_value))
    }
);
LucioFranco commented 2 years ago

Could you expand on what you're looking for?

ScottMichaud commented 1 year ago

There's 1,000,000,000 nanoseconds per second, not 1,000,000.