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 crate::lune::builtins::datetime::date_time::Timezone;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use chrono_locale::LocaleDate;
|
use chrono_locale::LocaleDate;
|
||||||
use mlua::prelude::*;
|
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[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 {
|
impl DateTimeBuilder {
|
||||||
/// Builder method to set the `Year`.
|
/// Builder method to set the `Year`.
|
||||||
pub fn with_year(&mut self, year: i32) -> &mut Self {
|
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.
|
/// 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
|
where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
|
@ -134,7 +113,7 @@ impl DateTimeBuilder {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
match timezone {
|
Ok(match timezone {
|
||||||
Timezone::Utc => Utc
|
Timezone::Utc => Utc
|
||||||
.with_ymd_and_hms(
|
.with_ymd_and_hms(
|
||||||
self.year,
|
self.year,
|
||||||
|
@ -144,7 +123,8 @@ impl DateTimeBuilder {
|
||||||
self.minute,
|
self.minute,
|
||||||
self.second,
|
self.second,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.single()
|
||||||
|
.ok_or(())?
|
||||||
.formatl((*format_lazy).as_str(), (*locale_lazy).as_str())
|
.formatl((*format_lazy).as_str(), (*locale_lazy).as_str())
|
||||||
.to_string(),
|
.to_string(),
|
||||||
Timezone::Local => Local
|
Timezone::Local => Local
|
||||||
|
@ -156,50 +136,14 @@ impl DateTimeBuilder {
|
||||||
self.minute,
|
self.minute,
|
||||||
self.second,
|
self.second,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.single()
|
||||||
|
.ok_or(())?
|
||||||
.formatl((*format_lazy).as_str(), (*locale_lazy).as_str())
|
.formatl((*format_lazy).as_str(), (*locale_lazy).as_str())
|
||||||
.to_string(),
|
.to_string(),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build(self) -> Self {
|
pub fn build(self) -> 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())
|
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
|
/// Formats a date as a ISO 8601 date-time string, returns None if the DateTime object is invalid.
|
||||||
/// function could be passed to `from_local_time` to produce the original `DateTime`
|
/// The value returned by this function could be passed to `from_local_time` to produce the
|
||||||
/// object.
|
/// original `DateTime` object.
|
||||||
pub fn to_iso_date(&self) -> String {
|
pub fn to_iso_date(&self) -> Result<String, ()> {
|
||||||
self.to_universal_time()
|
self.to_universal_time()
|
||||||
.to_string::<&str>(Timezone::Utc, None, None)
|
.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
|
/// and a format string. The format string should contain tokens, which will
|
||||||
/// replace to certain date/time values described by the `DateTime` object.
|
/// 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).
|
/// 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
|
where
|
||||||
T: ToString,
|
T: ToString,
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use chrono::Month;
|
||||||
use mlua::prelude::*;
|
use mlua::prelude::*;
|
||||||
|
|
||||||
pub(crate) mod builder;
|
pub(crate) mod builder;
|
||||||
|
@ -10,7 +11,6 @@ use self::{
|
||||||
use crate::lune::util::TableBuilder;
|
use crate::lune::util::TableBuilder;
|
||||||
|
|
||||||
// TODO: Proper error handling and stuff
|
// TODO: Proper error handling and stuff
|
||||||
// FIX: fromUnixTimestamp calculation is broken
|
|
||||||
|
|
||||||
pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
||||||
TableBuilder::new(lua)?
|
TableBuilder::new(lua)?
|
||||||
|
@ -19,11 +19,9 @@ pub fn create(lua: &'static Lua) -> LuaResult<LuaTable> {
|
||||||
let timestamp_cloned = timestamp.clone();
|
let timestamp_cloned = timestamp.clone();
|
||||||
let timestamp_kind = TimestampType::from_lua(timestamp, lua)?;
|
let timestamp_kind = TimestampType::from_lua(timestamp, lua)?;
|
||||||
let timestamp = match timestamp_kind {
|
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 => {
|
TimestampType::Millis => {
|
||||||
// FIXME: Remove the unwrap
|
let timestamp = timestamp_cloned.as_f64().ok_or(LuaError::external("invalid float timestamp with millis component supplied"))?;
|
||||||
// If something breaks, blame this.
|
|
||||||
let timestamp = timestamp_cloned.as_f64().unwrap();
|
|
||||||
|
|
||||||
((((timestamp - timestamp.fract()) as u64) * 1000_u64) // converting the whole seconds part to millis
|
((((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
|
// 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()))
|
Ok(DateTime::from_local_time(DateTimeBuilder::from_lua(date_time, lua).ok()))
|
||||||
})?
|
})?
|
||||||
.with_function("toLocalTime", |_, this: DateTime| {
|
.with_function("toLocalTime", |_, this: DateTime| {
|
||||||
Ok(this.to_local_time())
|
Ok(DateTime::to_local_time(&this))
|
||||||
})?
|
})?
|
||||||
.with_function("fromIsoDate", |_, iso_date: LuaString| {
|
.with_function("fromIsoDate", |_, iso_date: LuaString| {
|
||||||
Ok(DateTime::from_iso_date(iso_date.to_string_lossy()))
|
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(
|
.with_function(
|
||||||
"formatTime",
|
"formatTime",
|
||||||
|_, (this, timezone, fmt_str, locale): (DateTime, LuaValue, LuaString, LuaString)| {
|
|_, (this, timezone, fmt_str, locale): (DateTime, LuaValue, LuaString, LuaString)| {
|
||||||
Ok(this.format_time(
|
Ok(DateTime::format_time(
|
||||||
|
&this,
|
||||||
Timezone::from_lua(timezone, lua)?,
|
Timezone::from_lua(timezone, lua)?,
|
||||||
fmt_str.to_string_lossy(),
|
fmt_str.to_string_lossy(),
|
||||||
locale.to_string_lossy(),
|
locale.to_string_lossy(),
|
||||||
))
|
).map_err(|()| LuaError::external(
|
||||||
|
"failed to parse DateTime object, invalid",
|
||||||
|
)))
|
||||||
},
|
},
|
||||||
)?
|
)?
|
||||||
.build_readonly()
|
.build_readonly()
|
||||||
|
@ -103,16 +106,22 @@ impl LuaUserData for DateTime {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
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(
|
methods.add_method(
|
||||||
"formatTime",
|
"formatTime",
|
||||||
|_, this, (timezone, fmt_str, locale): (LuaValue, LuaString, LuaString)| {
|
|_, this, (timezone, fmt_str, locale): (LuaValue, LuaString, LuaString)| {
|
||||||
Ok(this.format_time(
|
Ok(this
|
||||||
Timezone::from_lua(timezone, &Lua::new())?,
|
.format_time(
|
||||||
fmt_str.to_string_lossy(),
|
Timezone::from_lua(timezone, &Lua::new())?,
|
||||||
locale.to_string_lossy(),
|
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