Skip to content

Commit

Permalink
Move lifetime from AsChunk<'a> to AsChunk::source
Browse files Browse the repository at this point in the history
  • Loading branch information
khvzak committed Jan 28, 2025
1 parent 8574682 commit 58965c6
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 45 deletions.
4 changes: 2 additions & 2 deletions mlua_derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ pub fn chunk(input: TokenStream) -> TokenStream {

struct InnerChunk<F: FnOnce(&Lua) -> Result<Table>>(Cell<Option<F>>);

impl<F> AsChunk<'static> for InnerChunk<F>
impl<F> AsChunk for InnerChunk<F>
where
F: FnOnce(&Lua) -> Result<Table>,
{
Expand All @@ -120,7 +120,7 @@ pub fn chunk(input: TokenStream) -> TokenStream {
Some(ChunkMode::Text)
}

fn source(self) -> IoResult<Cow<'static, [u8]>> {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Borrowed((#source).as_bytes()))
}
}
Expand Down
92 changes: 51 additions & 41 deletions src/chunk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::borrow::Cow;
use std::collections::HashMap;
use std::ffi::CString;
use std::io::Result as IoResult;
use std::marker::PhantomData;
use std::panic::Location;
use std::path::{Path, PathBuf};
use std::string::String as StdString;
Expand All @@ -17,7 +16,7 @@ use crate::value::Value;
/// Trait for types [loadable by Lua] and convertible to a [`Chunk`]
///
/// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2
pub trait AsChunk<'a> {
pub trait AsChunk {
/// Returns optional chunk name
///
/// See [`Chunk::set_name`] for possible name prefixes.
Expand All @@ -39,61 +38,75 @@ pub trait AsChunk<'a> {
}

/// Returns chunk data (can be text or binary)
fn source(self) -> IoResult<Cow<'a, [u8]>>;
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
where
Self: 'a;
}

impl<'a> AsChunk<'a> for &'a str {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
impl AsChunk for &str {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
where
Self: 'a,
{
Ok(Cow::Borrowed(self.as_ref()))
}
}

impl AsChunk<'static> for StdString {
fn source(self) -> IoResult<Cow<'static, [u8]>> {
impl AsChunk for StdString {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Owned(self.into_bytes()))
}
}

impl<'a> AsChunk<'a> for &'a StdString {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
impl AsChunk for &StdString {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
where
Self: 'a,
{
Ok(Cow::Borrowed(self.as_bytes()))
}
}

impl<'a> AsChunk<'a> for &'a [u8] {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
impl AsChunk for &[u8] {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
where
Self: 'a,
{
Ok(Cow::Borrowed(self))
}
}

impl AsChunk<'static> for Vec<u8> {
fn source(self) -> IoResult<Cow<'static, [u8]>> {
impl AsChunk for Vec<u8> {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Owned(self))
}
}

impl<'a> AsChunk<'a> for &'a Vec<u8> {
fn source(self) -> IoResult<Cow<'a, [u8]>> {
Ok(Cow::Borrowed(self.as_ref()))
impl AsChunk for &Vec<u8> {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>>
where
Self: 'a,
{
Ok(Cow::Borrowed(self))
}
}

impl AsChunk<'static> for &Path {
impl AsChunk for &Path {
fn name(&self) -> Option<StdString> {
Some(format!("@{}", self.display()))
}

fn source(self) -> IoResult<Cow<'static, [u8]>> {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
std::fs::read(self).map(Cow::Owned)
}
}

impl AsChunk<'static> for PathBuf {
impl AsChunk for PathBuf {
fn name(&self) -> Option<StdString> {
Some(format!("@{}", self.display()))
}

fn source(self) -> IoResult<Cow<'static, [u8]>> {
fn source<'a>(self) -> IoResult<Cow<'a, [u8]>> {
std::fs::read(self).map(Cow::Owned)
}
}
Expand Down Expand Up @@ -506,10 +519,10 @@ impl Chunk<'_> {
if self.detect_mode() == ChunkMode::Binary {
let lua = self.lua.lock();
if let Some(mut cache) = lua.app_data_mut_unguarded::<ChunksCache>() {
cache.0.insert(text_source, binary_source.as_ref().to_vec());
cache.0.insert(text_source, binary_source.to_vec());
} else {
let mut cache = ChunksCache(HashMap::new());
cache.0.insert(text_source, binary_source.as_ref().to_vec());
cache.0.insert(text_source, binary_source.to_vec());
let _ = lua.try_set_app_data(cache);
};
}
Expand Down Expand Up @@ -543,21 +556,20 @@ impl Chunk<'_> {
}

fn detect_mode(&self) -> ChunkMode {
match (self.mode, &self.source) {
(Some(mode), _) => mode,
(None, Ok(source)) => {
#[cfg(not(feature = "luau"))]
if source.starts_with(ffi::LUA_SIGNATURE) {
return ChunkMode::Binary;
}
#[cfg(feature = "luau")]
if *source.first().unwrap_or(&u8::MAX) < b'\n' {
return ChunkMode::Binary;
}
ChunkMode::Text
if let Some(mode) = self.mode {
return mode;
}
if let Ok(source) = &self.source {
#[cfg(not(feature = "luau"))]
if source.starts_with(ffi::LUA_SIGNATURE) {
return ChunkMode::Binary;
}
#[cfg(feature = "luau")]
if *source.first().unwrap_or(&u8::MAX) < b'\n' {
return ChunkMode::Binary;
}
(None, Err(_)) => ChunkMode::Text, // any value is fine
}
ChunkMode::Text
}

fn convert_name(name: String) -> Result<CString> {
Expand All @@ -572,29 +584,27 @@ impl Chunk<'_> {
}
}

struct WrappedChunk<'a, T: AsChunk<'a>> {
struct WrappedChunk<T: AsChunk> {
chunk: T,
caller: &'static Location<'static>,
_marker: PhantomData<&'a T>,
}

impl<'a> Chunk<'a> {
impl Chunk<'_> {
/// Wraps a chunk of Lua code, returning an opaque type that implements [`IntoLua`] trait.
///
/// The resulted `IntoLua` implementation will convert the chunk into a Lua function without
/// executing it.
#[doc(hidden)]
#[track_caller]
pub fn wrap(chunk: impl AsChunk<'a> + 'a) -> impl IntoLua + 'a {
pub fn wrap(chunk: impl AsChunk) -> impl IntoLua {
WrappedChunk {
chunk,
caller: Location::caller(),
_marker: PhantomData,
}
}
}

impl<'a, T: AsChunk<'a>> IntoLua for WrappedChunk<'a, T> {
impl<T: AsChunk> IntoLua for WrappedChunk<T> {
fn into_lua(self, lua: &Lua) -> Result<Value> {
lua.load_with_location(self.chunk, self.caller)
.into_function()
Expand Down
4 changes: 2 additions & 2 deletions src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -999,13 +999,13 @@ impl Lua {
///
/// [`Chunk::exec`]: crate::Chunk::exec
#[track_caller]
pub fn load<'a>(&self, chunk: impl AsChunk<'a>) -> Chunk<'a> {
pub fn load<'a>(&self, chunk: impl AsChunk + 'a) -> Chunk<'a> {
self.load_with_location(chunk, Location::caller())
}

pub(crate) fn load_with_location<'a>(
&self,
chunk: impl AsChunk<'a>,
chunk: impl AsChunk + 'a,
location: &'static Location<'static>,
) -> Chunk<'a> {
Chunk {
Expand Down

0 comments on commit 58965c6

Please sign in to comment.