Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to mlua v0.10 and overhaul Lua module creation #31

Merged
merged 8 commits into from
Oct 25, 2024
Merged
22 changes: 15 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,18 @@ strum = "0.26"
strum_macros = "0.26"
unicode_titlecase = "2.3"

[dependencies.anyhow]
version = "1.0"

[dependencies.clap]
version = "4.5"
optional = true
features = ["derive", "wrap_help"]

[dependencies.mlua]
version = "0.9"
version = "0.10.0"
optional = true
features = ["module"]
features = ["module", "anyhow"]

[dependencies.pyo3]
version = "0.22"
Expand Down
6 changes: 3 additions & 3 deletions src/content.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use crate::types::Result;
use regex::Regex;
use std::{borrow::Cow, error, fmt, fmt::Display, str::FromStr};
use std::{borrow::Cow, fmt, fmt::Display, str::FromStr};

#[derive(Clone, Debug, PartialEq)]
#[non_exhaustive]
Expand All @@ -12,7 +12,7 @@ pub enum Segment {
Word(String),
}

#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct Chunk {
pub segments: Vec<Segment>,
Expand Down Expand Up @@ -56,7 +56,7 @@ impl From<&Cow<'_, str>> for Chunk {
}

impl FromStr for Chunk {
type Err = Box<dyn error::Error>;
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
Ok(split_chunk(s))
}
Expand Down
140 changes: 53 additions & 87 deletions src/lua.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,102 +8,68 @@ pub use crate::types::{Case, Locale, Result, StyleGuide};

#[mlua::lua_module]
fn decasify(lua: &Lua) -> LuaResult<LuaTable> {
let exports = lua.create_table().unwrap();
let case = lua.create_function(case)?;
exports.set("case", case).unwrap();
let titlecase = lua.create_function(titlecase)?;
exports.set("titlecase", titlecase).unwrap();
let lowercase = lua.create_function(lowercase)?;
exports.set("lowercase", lowercase).unwrap();
let uppercase = lua.create_function(uppercase)?;
exports.set("uppercase", uppercase).unwrap();
let sentencecase = lua.create_function(sentencecase)?;
exports.set("sentencecase", sentencecase).unwrap();
let exports = lua.create_table()?;
exports.set(
"case",
LuaFunction::wrap_raw::<_, (Chunk, Case, Locale, StyleGuide)>(to_case),
)?;
exports.set(
"titlecase",
LuaFunction::wrap_raw::<_, (Chunk, Locale, StyleGuide)>(to_titlecase),
)?;
exports.set(
"lowercase",
LuaFunction::wrap_raw::<_, (Chunk, Locale)>(to_lowercase),
)?;
exports.set(
"uppercase",
LuaFunction::wrap_raw::<_, (Chunk, Locale)>(to_uppercase),
)?;
exports.set(
"sentencecase",
LuaFunction::wrap_raw::<_, (Chunk, Locale)>(to_sentencecase),
)?;
let version = option_env!("VERGEN_GIT_DESCRIBE").unwrap_or_else(|| env!("CARGO_PKG_VERSION"));
let version = lua.create_string(version)?;
exports.set("version", version).unwrap();
exports.set("version", version)?;
Ok(exports)
}

fn case<'a>(
lua: &'a Lua,
(input, case, locale, style): (LuaString<'a>, LuaValue<'a>, LuaValue<'a>, LuaValue<'a>),
) -> LuaResult<LuaString<'a>> {
let input = input.to_string_lossy();
let case: Case = match case {
LuaValue::String(s) => s.to_string_lossy().parse().unwrap_or(Case::Title),
_ => Case::Title,
};
let locale: Locale = match locale {
LuaValue::String(s) => s.to_string_lossy().parse().unwrap_or(Locale::EN),
_ => Locale::EN,
};
let style: StyleGuide = match style {
LuaValue::String(s) => s
.to_string_lossy()
.parse()
.unwrap_or(StyleGuide::LanguageDefault),
_ => StyleGuide::LanguageDefault,
};
let output = to_case(&input, case, locale, style);
lua.create_string(output)
impl FromLua for Chunk {
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
match value {
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
_ => Ok("".into()),
}
}
}

fn titlecase<'a>(
lua: &'a Lua,
(input, locale, style): (LuaString<'a>, LuaValue<'a>, LuaValue<'a>),
) -> LuaResult<LuaString<'a>> {
let input = input.to_string_lossy();
let locale: Locale = match locale {
LuaValue::String(s) => s.to_string_lossy().parse().unwrap_or(Locale::EN),
_ => Locale::EN,
};
let style: StyleGuide = match style {
LuaValue::String(s) => s
.to_string_lossy()
.parse()
.unwrap_or(StyleGuide::LanguageDefault),
_ => StyleGuide::LanguageDefault,
};
let output = to_titlecase(&input, locale, style);
lua.create_string(output)
impl FromLua for Locale {
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
match value {
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
LuaValue::Nil => Ok(Self::default()),
_ => unimplemented!(),
}
}
}

fn lowercase<'a>(
lua: &'a Lua,
(input, locale): (LuaString<'a>, LuaValue<'a>),
) -> LuaResult<LuaString<'a>> {
let input = input.to_string_lossy();
let locale: Locale = match locale {
LuaValue::String(s) => s.to_string_lossy().parse().unwrap_or(Locale::EN),
_ => Locale::EN,
};
let output = to_lowercase(&input, locale);
lua.create_string(output)
impl FromLua for Case {
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
match value {
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
LuaValue::Nil => Ok(Self::default()),
_ => unimplemented!(),
}
}
}

fn uppercase<'a>(
lua: &'a Lua,
(input, locale): (LuaString<'a>, LuaValue<'a>),
) -> LuaResult<LuaString<'a>> {
let input = input.to_string_lossy();
let locale: Locale = match locale {
LuaValue::String(s) => s.to_string_lossy().parse().unwrap_or(Locale::EN),
_ => Locale::EN,
};
let output = to_uppercase(&input, locale);
lua.create_string(output)
}

fn sentencecase<'a>(
lua: &'a Lua,
(input, locale): (LuaString<'a>, LuaValue<'a>),
) -> LuaResult<LuaString<'a>> {
let input = input.to_string_lossy();
let locale: Locale = match locale {
LuaValue::String(s) => s.to_string_lossy().parse().unwrap_or(Locale::EN),
_ => Locale::EN,
};
let output = to_sentencecase(&input, locale);
lua.create_string(output)
impl FromLua for StyleGuide {
fn from_lua(value: LuaValue, _: &Lua) -> LuaResult<Self> {
match value {
LuaValue::String(s) => Ok(s.to_string_lossy().into()),
LuaValue::Nil => Ok(Self::default()),
_ => unimplemented!(),
}
}
}
22 changes: 11 additions & 11 deletions src/types.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: © 2023 Caleb Maclennan <[email protected]>
// SPDX-License-Identifier: LGPL-3.0-only

use std::{error, fmt, fmt::Display, result, str::FromStr};
use std::{error, fmt, fmt::Display, str::FromStr};
use strum_macros::{Display, VariantNames};

#[cfg(feature = "pythonmodule")]
Expand All @@ -10,7 +10,7 @@ use pyo3::prelude::*;
#[cfg(feature = "wasm")]
use wasm_bindgen::prelude::*;

pub type Result<T> = result::Result<T, Box<dyn error::Error>>;
pub type Result<T> = anyhow::Result<T>;

#[derive(Debug)]
pub struct Error(pub String);
Expand Down Expand Up @@ -68,12 +68,12 @@ pub enum StyleGuide {
}

impl FromStr for Locale {
type Err = Box<dyn error::Error>;
fn from_str(s: &str) -> Result<Self> {
type Err = anyhow::Error;
fn from_str(s: &str) -> crate::Result<Self> {
match s.to_ascii_lowercase().as_str() {
"en" | "English" | "en_en" => Ok(Locale::EN),
"tr" | "Turkish" | "tr_tr" | "türkçe" => Ok(Locale::TR),
_ => Err(Box::new(Error("Invalid input language".into()))),
_ => Err(anyhow::Error::new(Error("Invalid input language".into()))),
}
}
}
Expand All @@ -97,14 +97,14 @@ impl From<&String> for Locale {
}

impl FromStr for Case {
type Err = Box<dyn error::Error>;
fn from_str(s: &str) -> Result<Self> {
type Err = anyhow::Error;
fn from_str(s: &str) -> crate::Result<Self> {
match s.to_ascii_lowercase().as_str().trim_end_matches("case") {
"lower" => Ok(Case::Lower),
"sentence" => Ok(Case::Sentence),
"title" => Ok(Case::Title),
"upper" => Ok(Case::Upper),
_ => Err(Box::new(Error("Unknown target case".into()))),
_ => Err(anyhow::Error::new(Error("Unknown target case".into()))),
}
}
}
Expand All @@ -128,16 +128,16 @@ impl From<&String> for Case {
}

impl FromStr for StyleGuide {
type Err = Box<dyn error::Error>;
fn from_str(s: &str) -> Result<Self> {
type Err = anyhow::Error;
fn from_str(s: &str) -> crate::Result<Self> {
match s.to_ascii_lowercase().as_str() {
"daringfireball" | "gruber" | "fireball" => Ok(StyleGuide::DaringFireball),
"associatedpress" | "ap" => Ok(StyleGuide::AssociatedPress),
"chicagoManualofstyle" | "chicago" | "cmos" => Ok(StyleGuide::ChicagoManualOfStyle),
"default" | "languagedefault" | "language" | "none" | "" => {
Ok(StyleGuide::LanguageDefault)
}
_ => Err(Box::new(Error("Invalid style guide".into()))),
_ => Err(anyhow::Error::new(Error("Invalid style guide".into()))),
}
}
}
Expand Down
Loading