mirror of
https://github.com/lune-org/lune.git
synced 2025-05-04 10:43:57 +01:00
feat: proper error handling & error propagation
This commit is contained in:
parent
6b4000d253
commit
e4a65e301b
3 changed files with 104 additions and 89 deletions
|
@ -1,7 +1,6 @@
|
|||
use crate::lune::builtins::datetime::date_time::Timezone;
|
||||
use chrono::prelude::*;
|
||||
use chrono_locale::LocaleDate;
|
||||
use mlua::prelude::*;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
|
@ -37,31 +36,6 @@ impl Default for DateTimeBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Timezone {
|
||||
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
|
||||
fn num_to_enum(num: i32) -> LuaResult<Timezone> {
|
||||
match num {
|
||||
1 => Ok(Timezone::Utc),
|
||||
2 => Ok(Timezone::Local),
|
||||
_ => Err(LuaError::external("Invalid enum member!")),
|
||||
}
|
||||
}
|
||||
|
||||
match value {
|
||||
LuaValue::Integer(num) => num_to_enum(num),
|
||||
LuaValue::Number(num) => num_to_enum(num as i32),
|
||||
LuaValue::String(str) => match str.to_str()?.to_lowercase().as_str() {
|
||||
"utc" => Ok(Timezone::Utc),
|
||||
"local" => Ok(Timezone::Local),
|
||||
&_ => Err(LuaError::external("Invalid enum member!")),
|
||||
},
|
||||
_ => Err(LuaError::external(
|
||||
"Invalid enum type, number or string expected",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DateTimeBuilder {
|
||||
/// Builder method to set the `Year`.
|
||||
pub fn with_year(&mut self, year: i32) -> &mut Self {
|
||||
|
@ -114,7 +88,12 @@ impl DateTimeBuilder {
|
|||
}
|
||||
|
||||
/// Converts the `DateTimeBuilder` to a string with a specified format and locale.
|
||||
pub fn to_string<T>(self, timezone: Timezone, format: Option<T>, locale: Option<T>) -> String
|
||||
pub fn to_string<T>(
|
||||
self,
|
||||
timezone: Timezone,
|
||||
format: Option<T>,
|
||||
locale: Option<T>,
|
||||
) -> Result<String, ()>
|
||||
where
|
||||
T: ToString,
|
||||
{
|
||||
|
@ -134,7 +113,7 @@ impl DateTimeBuilder {
|
|||
}
|
||||
});
|
||||
|
||||
match timezone {
|
||||
Ok(match timezone {
|
||||
Timezone::Utc => Utc
|
||||
.with_ymd_and_hms(
|
||||
self.year,
|
||||
|
@ -144,7 +123,8 @@ impl DateTimeBuilder {
|
|||
self.minute,
|
||||
self.second,
|
||||
)
|
||||
.unwrap()
|
||||
.single()
|
||||
.ok_or(())?
|
||||
.formatl((*format_lazy).as_str(), (*locale_lazy).as_str())
|
||||
.to_string(),
|
||||
Timezone::Local => Local
|
||||
|
@ -156,50 +136,14 @@ impl DateTimeBuilder {
|
|||
self.minute,
|
||||
self.second,
|
||||
)
|
||||
.unwrap()
|
||||
.single()
|
||||
.ok_or(())?
|
||||
.formatl((*format_lazy).as_str(), (*locale_lazy).as_str())
|
||||
.to_string(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn build(self) -> Self {
|
||||
pub fn build(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaUserData for DateTimeBuilder {}
|
||||
|
||||
impl<'lua> FromLua<'lua> for DateTimeBuilder {
|
||||
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
|
||||
match value {
|
||||
LuaValue::Table(t) => Ok(Self::default()
|
||||
.with_year(t.get("year")?)
|
||||
.with_month(
|
||||
(match t.get("month")? {
|
||||
LuaValue::String(str) => Ok(str.to_str()?.parse::<Month>().or(Err(
|
||||
LuaError::external("could not cast month string to Month"),
|
||||
))?),
|
||||
LuaValue::Nil => {
|
||||
Err(LuaError::external("cannot find mandatory month argument"))
|
||||
}
|
||||
LuaValue::Number(num) => Ok(Month::try_from(num as u8).or(Err(
|
||||
LuaError::external("could not cast month number to Month"),
|
||||
))?),
|
||||
LuaValue::Integer(int) => Ok(Month::try_from(int as u8).or(Err(
|
||||
LuaError::external("could not cast month integer to Month"),
|
||||
))?),
|
||||
_ => Err(LuaError::external("unexpected month field type")),
|
||||
})?,
|
||||
)
|
||||
.with_day(t.get("day")?)
|
||||
.with_hour(t.get("hour")?)
|
||||
.with_minute(t.get("minute")?)
|
||||
.with_second(t.get("second")?)
|
||||
// TODO: millisecond support
|
||||
.build()),
|
||||
_ => Err(LuaError::external(
|
||||
"expected type table for DateTimeBuilder",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -211,10 +211,10 @@ impl DateTime {
|
|||
Self::to_datetime_builder(Utc.timestamp_opt(self.unix_timestamp, 0).unwrap())
|
||||
}
|
||||
|
||||
/// Formats a date as a ISO 8601 date-time string. The value returned by this
|
||||
/// function could be passed to `from_local_time` to produce the original `DateTime`
|
||||
/// object.
|
||||
pub fn to_iso_date(&self) -> String {
|
||||
/// Formats a date as a ISO 8601 date-time string, returns None if the DateTime object is invalid.
|
||||
/// The value returned by this function could be passed to `from_local_time` to produce the
|
||||
/// original `DateTime` object.
|
||||
pub fn to_iso_date(&self) -> Result<String, ()> {
|
||||
self.to_universal_time()
|
||||
.to_string::<&str>(Timezone::Utc, None, None)
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ impl DateTime {
|
|||
/// and a format string. The format string should contain tokens, which will
|
||||
/// replace to certain date/time values described by the `DateTime` object.
|
||||
/// For more details, see the [accepted formatter tokens](https://docs.rs/chrono/latest/chrono/format/strftime/index.html).
|
||||
pub fn format_time<T>(&self, timezone: Timezone, fmt_str: T, locale: T) -> String
|
||||
pub fn format_time<T>(&self, timezone: Timezone, fmt_str: T, locale: T) -> Result<String, ()>
|
||||
where
|
||||
T: ToString,
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use chrono::Month;
|
||||
use mlua::prelude::*;
|
||||
|
||||
pub(crate) mod builder;
|
||||
|
@ -10,7 +11,6 @@ use self::{
|
|||
use crate::lune::util::TableBuilder;
|
||||
|
||||
// TODO: Proper error handling and stuff
|
||||
// FIX: fromUnixTimestamp calculation is broken
|
||||
|
||||
pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
||||
TableBuilder::new(lua)?
|
||||
|
@ -19,11 +19,9 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
|||
let timestamp_cloned = timestamp.clone();
|
||||
let timestamp_kind = TimestampType::from_lua(timestamp, lua)?;
|
||||
let timestamp = match timestamp_kind {
|
||||
TimestampType::Seconds => timestamp_cloned.as_i64().unwrap(),
|
||||
TimestampType::Seconds => timestamp_cloned.as_i64().ok_or(LuaError::external("invalid float integer timestamp supplied"))?,
|
||||
TimestampType::Millis => {
|
||||
// FIXME: Remove the unwrap
|
||||
// If something breaks, blame this.
|
||||
let timestamp = timestamp_cloned.as_f64().unwrap();
|
||||
let timestamp = timestamp_cloned.as_f64().ok_or(LuaError::external("invalid float timestamp with millis component supplied"))?;
|
||||
|
||||
((((timestamp - timestamp.fract()) as u64) * 1000_u64) // converting the whole seconds part to millis
|
||||
// the ..3 gets a &str of the first 3 chars of the digits after the decimals, ignoring
|
||||
|
@ -47,20 +45,25 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
|||
Ok(DateTime::from_local_time(DateTimeBuilder::from_lua(date_time, lua).ok()))
|
||||
})?
|
||||
.with_function("toLocalTime", |_, this: DateTime| {
|
||||
Ok(this.to_local_time())
|
||||
Ok(DateTime::to_local_time(&this))
|
||||
})?
|
||||
.with_function("fromIsoDate", |_, iso_date: LuaString| {
|
||||
Ok(DateTime::from_iso_date(iso_date.to_string_lossy()))
|
||||
})?
|
||||
.with_function("toIsoDate", |_, this| Ok(DateTime::to_iso_date(&this)))?
|
||||
.with_function("toIsoDate", |_, this| Ok(DateTime::to_iso_date(&this).map_err(|()| LuaError::external(
|
||||
"failed to parse DateTime object, invalid",
|
||||
))))?
|
||||
.with_function(
|
||||
"formatTime",
|
||||
|_, (this, timezone, fmt_str, locale): (DateTime, LuaValue, LuaString, LuaString)| {
|
||||
Ok(this.format_time(
|
||||
Ok(DateTime::format_time(
|
||||
&this,
|
||||
Timezone::from_lua(timezone, lua)?,
|
||||
fmt_str.to_string_lossy(),
|
||||
locale.to_string_lossy(),
|
||||
))
|
||||
).map_err(|()| LuaError::external(
|
||||
"failed to parse DateTime object, invalid",
|
||||
)))
|
||||
},
|
||||
)?
|
||||
.build_readonly()
|
||||
|
@ -103,16 +106,22 @@ impl LuaUserData for DateTime {
|
|||
}
|
||||
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_method("toIsoDate", |_, this, ()| Ok(this.to_iso_date()));
|
||||
methods.add_method("toIsoDate", |_, this, ()| {
|
||||
Ok(this
|
||||
.to_iso_date()
|
||||
.map_err(|()| LuaError::external("failed to parse DateTime object, invalid")))
|
||||
});
|
||||
|
||||
methods.add_method(
|
||||
"formatTime",
|
||||
|_, this, (timezone, fmt_str, locale): (LuaValue, LuaString, LuaString)| {
|
||||
Ok(this.format_time(
|
||||
Timezone::from_lua(timezone, &Lua::new())?,
|
||||
fmt_str.to_string_lossy(),
|
||||
locale.to_string_lossy(),
|
||||
))
|
||||
Ok(this
|
||||
.format_time(
|
||||
Timezone::from_lua(timezone, &Lua::new())?,
|
||||
fmt_str.to_string_lossy(),
|
||||
locale.to_string_lossy(),
|
||||
)
|
||||
.map_err(|()| LuaError::external("failed to parse DateTime object, invalid")))
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -138,3 +147,65 @@ impl<'lua> FromLua<'lua> for DateTime {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaUserData for DateTimeBuilder {}
|
||||
|
||||
impl<'lua> FromLua<'lua> for DateTimeBuilder {
|
||||
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
|
||||
match value {
|
||||
LuaValue::Table(t) => Ok(Self::default()
|
||||
.with_year(t.get("year")?)
|
||||
.with_month(
|
||||
(match t.get("month")? {
|
||||
LuaValue::String(str) => Ok(str.to_str()?.parse::<Month>().or(Err(
|
||||
LuaError::external("could not cast month string to Month"),
|
||||
))?),
|
||||
LuaValue::Nil => {
|
||||
Err(LuaError::external("cannot find mandatory month argument"))
|
||||
}
|
||||
LuaValue::Number(num) => Ok(Month::try_from(num as u8).or(Err(
|
||||
LuaError::external("could not cast month number to Month"),
|
||||
))?),
|
||||
LuaValue::Integer(int) => Ok(Month::try_from(int as u8).or(Err(
|
||||
LuaError::external("could not cast month integer to Month"),
|
||||
))?),
|
||||
_ => Err(LuaError::external("unexpected month field type")),
|
||||
})?,
|
||||
)
|
||||
.with_day(t.get("day")?)
|
||||
.with_hour(t.get("hour")?)
|
||||
.with_minute(t.get("minute")?)
|
||||
.with_second(t.get("second")?)
|
||||
// TODO: millisecond support
|
||||
.build()),
|
||||
_ => Err(LuaError::external(
|
||||
"expected type table for DateTimeBuilder",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'lua> FromLua<'lua> for Timezone {
|
||||
fn from_lua(value: LuaValue<'lua>, _: &'lua Lua) -> LuaResult<Self> {
|
||||
fn num_to_enum(num: i32) -> LuaResult<Timezone> {
|
||||
match num {
|
||||
1 => Ok(Timezone::Utc),
|
||||
2 => Ok(Timezone::Local),
|
||||
_ => Err(LuaError::external("Invalid enum member!")),
|
||||
}
|
||||
}
|
||||
|
||||
match value {
|
||||
LuaValue::Integer(num) => num_to_enum(num),
|
||||
LuaValue::Number(num) => num_to_enum(num as i32),
|
||||
LuaValue::String(str) => match str.to_str()?.to_lowercase().as_str() {
|
||||
"utc" => Ok(Timezone::Utc),
|
||||
"local" => Ok(Timezone::Local),
|
||||
&_ => Err(LuaError::external("Invalid enum member!")),
|
||||
},
|
||||
_ => Err(LuaError::external(
|
||||
"Invalid enum type, number or string expected",
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue