use std::str::FromStr;
use anyhow::{Result, bail};
use bc_components::{ARID, Digest};
use bc_envelope::prelude::*;
use clap::ValueEnum;
#[derive(ValueEnum, Copy, Clone, Debug, PartialEq, Eq)]
pub enum DataType {
Arid,
Bool,
Cbor,
Data,
Date,
Digest,
Envelope,
Known,
Number,
String,
Unit,
Ur,
Uri,
Uuid,
Wrapped,
}
pub fn parse_data_type_to_envelope(
data_type: DataType,
s: Option<&str>,
ur_cbor_tag_value: Option<u64>,
) -> Result<Envelope> {
if data_type == DataType::Unit {
return Ok(Envelope::unit());
}
if let Some(s) = s {
match data_type {
DataType::Arid => parse_arid(s),
DataType::Bool => parse_boolean(s),
DataType::Cbor => parse_cbor(s),
DataType::Data => parse_data(s),
DataType::Date => parse_date(s),
DataType::Digest => parse_digest(s),
DataType::Envelope => parse_envelope(s),
DataType::Known => parse_known_value(s),
DataType::Number => parse_number(s),
DataType::String => parse_string(s),
DataType::Unit => unreachable!(),
DataType::Ur => parse_ur(s, ur_cbor_tag_value),
DataType::Uri => parse_uri(s),
DataType::Uuid => parse_uuid(s),
DataType::Wrapped => parse_wrapped_envelope(s),
}
} else {
bail!("No value provided")
}
}
fn parse_arid(s: &str) -> Result<Envelope> {
if let Ok(hex) = hex::decode(s) {
let arid = ARID::from_data_ref(hex)?;
Ok(Envelope::new(arid))
} else if let Ok(arid) = ARID::from_ur_string(s) {
Ok(Envelope::new(arid))
} else {
bail!("Invalid ARID")
}
}
fn parse_boolean(s: &str) -> Result<Envelope> {
let boolean = bool::from_str(s)?;
Ok(Envelope::new(boolean))
}
fn parse_cbor(s: &str) -> Result<Envelope> {
let cbor = CBOR::try_from_hex(s)?;
Ok(Envelope::new(cbor))
}
fn parse_data(s: &str) -> Result<Envelope> {
let data = CBOR::to_byte_string(hex::decode(s)?);
Ok(Envelope::new(data))
}
fn parse_date(s: &str) -> Result<Envelope> {
let date = Date::from_string(s)?;
Ok(Envelope::new(date))
}
fn parse_digest(s: &str) -> Result<Envelope> {
let digest = Digest::from_ur_string(s)?;
Ok(Envelope::new(digest))
}
fn parse_envelope(s: &str) -> Result<Envelope> { crate::read_envelope(Some(s)) }
fn parse_known_value(s: &str) -> Result<Envelope> {
if let Ok(number) = s.parse::<u64>() {
Ok(Envelope::new(KnownValue::new(number)))
} else {
with_format_context!(|context: &FormatContext| {
let store = context.known_values();
if let Some(known_value) =
KnownValuesStore::known_value_for_name(s, Some(store))
{
Ok(Envelope::new(known_value))
} else {
bail!("Unknown known value")
}
})
}
}
fn parse_number(s: &str) -> Result<Envelope> {
let number = s.parse::<f64>()?;
Ok(Envelope::new(number))
}
fn parse_string(s: &str) -> Result<Envelope> { Ok(Envelope::new(s)) }
fn parse_ur(s: &str, cbor_tag_value: Option<u64>) -> Result<Envelope> {
let ur = UR::from_ur_string(s)?;
if ur.ur_type_str() == "envelope" {
let envelope = Envelope::from_ur(&ur)?;
Ok(envelope.wrap())
} else if let Ok(envelope) = Envelope::from_tagged_cbor(ur.cbor()) {
Ok(envelope)
} else {
let cbor_tag = with_format_context!(|context: &FormatContext| {
let store = context.tags();
if let Some(tag) = store.tag_for_name(ur.ur_type_str()) {
Some(tag)
} else {
cbor_tag_value.map(Tag::with_value)
}
});
if let Some(cbor_tag) = cbor_tag {
let cbor = ur.to_cbor();
let content_cbor = CBOR::to_tagged_value(cbor_tag, cbor);
Ok(Envelope::new(content_cbor))
} else {
bail!("Unknown UR type")
}
}
}
fn parse_uri(s: &str) -> Result<Envelope> {
let uri = bc_components::URI::new(s)?;
Ok(Envelope::new(uri))
}
fn parse_uuid(s: &str) -> Result<Envelope> {
let uuid = bc_components::UUID::from_str(s)?;
Ok(Envelope::new(uuid))
}
fn parse_wrapped_envelope(s: &str) -> Result<Envelope> {
let envelope = crate::read_envelope(Some(s))?;
Ok(envelope.wrap())
}
pub fn parse_ur_to_cbor(s: &str, cbor_tag_value: Option<u64>) -> Result<CBOR> {
let ur = UR::from_ur_string(s)?;
let cbor_tag = with_format_context!(|context: &FormatContext| {
let store = context.tags();
if let Some(tag) = store.tag_for_name(ur.ur_type_str()) {
Some(tag)
} else {
cbor_tag_value.map(Tag::with_value)
}
});
if let Some(cbor_tag) = cbor_tag {
let cbor = ur.cbor();
Ok(CBOR::to_tagged_value(cbor_tag, cbor))
} else {
bail!(
"Unknown UR type: '{}'. Use --ur-tag to specify the CBOR tag value.",
ur.ur_type_str()
)
}
}