Skip to content

Commit

Permalink
Merge branch 'master' into unity_il2cpp
Browse files Browse the repository at this point in the history
  • Loading branch information
Jujstme authored Nov 19, 2023
2 parents bee916d + eeb9ef3 commit 11d7df0
Show file tree
Hide file tree
Showing 10 changed files with 897 additions and 50 deletions.
12 changes: 6 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ jobs:

steps:
- name: Checkout Commit
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install Rust
uses: hecrj/setup-rust-action@v1
uses: hecrj/setup-rust-action@v2
with:
rust-version: ${{ matrix.toolchain || 'stable' }}

Expand Down Expand Up @@ -67,10 +67,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Commit
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install Rust
uses: hecrj/setup-rust-action@v1
uses: hecrj/setup-rust-action@v2
with:
components: clippy

Expand All @@ -82,10 +82,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Commit
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Install Rust
uses: hecrj/setup-rust-action@v1
uses: hecrj/setup-rust-action@v2
with:
components: rustfmt

Expand Down
34 changes: 34 additions & 0 deletions asr-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,20 @@ use proc_macro::TokenStream;
use quote::{quote, quote_spanned};
use syn::{spanned::Spanned, Data, DeriveInput, Expr, ExprLit, Lit, Meta};

// FIXME: https://github.com/rust-lang/rust/issues/117463
#[allow(rustdoc::redundant_explicit_links)]
/// Implements the `Gui` trait for a struct that allows you to register its
/// fields as settings widgets and returns the struct with the user's settings
/// applied.
///
/// The name of each field is used as the key for the setting for storing it in
/// the global settings map and looking up the current value.
///
/// The first paragraph in the doc comment of each field is used as the
/// description of the setting. The rest of the doc comment is used as the
/// tooltip. If there is no doc comment, the name of the field is used as the
/// description (in title case).
///
/// # Example
///
/// ```no_run
Expand All @@ -31,6 +41,30 @@ use syn::{spanned::Spanned, Data, DeriveInput, Expr, ExprLit, Lit, Meta};
/// // Do something with the settings.
/// }
/// ```
///
/// # Attributes
///
/// The default value of the setting normally matches the
/// [`Default`](core::default::Default) trait. If you want to specify a
/// different default you can specify it like so:
///
/// ```no_run
/// # struct Settings {
/// #[default = true]
/// foo: bool,
/// # }
/// ```
///
/// The heading level of a title can be specified to form a hierarchy. The top
/// level titles use a heading level of 0. It is also the default heading level.
/// You can specify a different heading level like so:
///
/// ```no_run
/// # struct Settings {
/// #[heading_level = 2]
/// _title: Title,
/// # }
/// ```
#[proc_macro_derive(Gui, attributes(default, heading_level))]
pub fn settings_macro(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ extern crate alloc;
mod primitives;
mod runtime;

pub mod deep_pointer;
pub mod emulator;
#[macro_use]
pub mod future;
Expand All @@ -143,7 +144,6 @@ pub mod time_util;
#[cfg(all(feature = "wasi-no-std", target_os = "wasi"))]
mod wasi_no_std;
pub mod watcher;
pub mod deep_pointer;

pub use self::{primitives::*, runtime::*};
pub use arrayvec;
Expand Down
37 changes: 36 additions & 1 deletion src/runtime/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use super::{sys, Error, MemoryRange};
pub use super::sys::ProcessId;

/// A process that the auto splitter is attached to.
#[derive(Debug)]
#[repr(transparent)]
pub struct Process(pub(super) sys::Process);

Expand Down Expand Up @@ -194,6 +193,42 @@ impl Process {
}
}

/// Gets the path of a module in the file system. The path is a path that is
/// accessible through the WASI file system, so a Windows path of
/// `C:\foo\bar.dll` would be returned as `/mnt/c/foo/bar.dll`.
#[cfg(feature = "alloc")]
#[inline]
pub fn get_module_path(&self, name: &str) -> Result<alloc::string::String, Error> {
// SAFETY: Calling `process_get_module_path` with a null pointer and 0
// length will return the required length. We then allocate a buffer
// with the required length and call it again with the buffer. We then
// convert the buffer into a string, which is guaranteed to be valid
// UTF-8.
unsafe {
let mut len = 0;
sys::process_get_module_path(
self.0,
name.as_ptr(),
name.len(),
core::ptr::null_mut(),
&mut len,
);
let mut buf = alloc::vec::Vec::with_capacity(len);
let success = sys::process_get_module_path(
self.0,
name.as_ptr(),
name.len(),
buf.as_mut_ptr(),
&mut len,
);
if !success {
return Err(Error {});
}
buf.set_len(len);
Ok(alloc::string::String::from_utf8_unchecked(buf))
}
}

/// Gets the address and size of a module in the process.
#[inline]
pub fn get_module_range(&self, name: &str) -> Result<(Address, u64), Error> {
Expand Down
23 changes: 19 additions & 4 deletions src/runtime/settings/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#[cfg(feature = "derive")]
pub use asr_derive::Gui;

use crate::runtime::sys;
use crate::{runtime::sys, watcher::Pair};

use super::map::Map;

Expand Down Expand Up @@ -78,9 +78,7 @@ pub trait Gui {
fn update_from(&mut self, settings_map: &Map);
}

/// A settings widget that can be added to the settings GUI. This is an internal
/// trait that you don't need to worry about.
#[doc(hidden)]
/// A settings widget that can be used as a field when defining a settings [`Gui`].
pub trait Widget {
/// The arguments that are needed to register the widget.
type Args: Default;
Expand Down Expand Up @@ -146,3 +144,20 @@ impl Widget for Title {
#[inline]
fn update_from(&mut self, _settings_map: &Map, _key: &str, _args: Self::Args) {}
}

impl<T: Copy + Widget> Widget for Pair<T> {
type Args = T::Args;

fn register(key: &str, description: &str, args: Self::Args) -> Self {
let value = T::register(key, description, args);
Pair {
old: value,
current: value,
}
}

fn update_from(&mut self, settings_map: &Map, key: &str, args: Self::Args) {
self.old = self.current;
self.current.update_from(settings_map, key, args);
}
}
109 changes: 109 additions & 0 deletions src/runtime/settings/list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use core::fmt;

use crate::{runtime::sys, Error};

use super::Value;

/// A list of [`Value`]s that can itself be a [`Value`] and thus be stored in a
/// [`Map`](super::Map).
#[repr(transparent)]
pub struct List(pub(super) sys::SettingsList);

impl fmt::Debug for List {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish()
}
}

impl Drop for List {
#[inline]
fn drop(&mut self) {
// SAFETY: The handle is valid and we own it, so it's our responsibility
// to free it.
unsafe { sys::settings_list_free(self.0) }
}
}

impl Clone for List {
#[inline]
fn clone(&self) -> Self {
// SAFETY: The handle is valid, so we can safely copy it.
Self(unsafe { sys::settings_list_copy(self.0) })
}
}

impl Default for List {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl List {
/// Creates a new empty settings list.
#[inline]
pub fn new() -> Self {
// SAFETY: This is always safe to call.
Self(unsafe { sys::settings_list_new() })
}

/// Returns the number of values in the list.
#[inline]
pub fn len(&self) -> u64 {
// SAFETY: The handle is valid, so we can safely call this function.
unsafe { sys::settings_list_len(self.0) }
}

/// Returns [`true`] if the list has a length of 0.
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}

/// Returns a copy of the value at the given index. Returns [`None`] if the
/// index is out of bounds. Any changes to it are only perceived if it's
/// stored back.
#[inline]
pub fn get(&self, index: u64) -> Option<Value> {
// SAFETY: The settings list handle is valid.
unsafe { sys::settings_list_get(self.0, index).map(Value) }
}

/// Pushes a copy of the value to the end of the list.
#[inline]
pub fn push(&self, value: &Value) {
// SAFETY: The settings list handle is valid and the value handle is
// valid.
unsafe { sys::settings_list_push(self.0, value.0) }
}

/// Inserts a copy of the value at the given index, pushing all values at
/// and after the index one position further. Returns an error if the index
/// is out of bounds. You may specify an index that is equal to the length
/// of the list to append the value to the end of the list.
#[inline]
pub fn insert(&self, index: u64, value: &Value) -> Result<(), Error> {
// SAFETY: The settings list handle is valid and the value handle is
// valid.
unsafe {
if sys::settings_list_insert(self.0, index, value.0) {
Ok(())
} else {
Err(Error {})
}
}
}

/// Returns an iterator over the values in the list. Every value is a copy,
/// so any changes to them are only perceived if they are stored back. The
/// iterator is double-ended, so it can be iterated backwards as well. While
/// it's possible to modify the list while iterating over it, it's not
/// recommended to do so, as the iterator might skip values or return
/// duplicate values. In that case it's better to clone the list before and
/// iterate over the clone or use [`get`](Self::get) to manually handle the
/// iteration.
#[inline]
pub fn iter(&self) -> impl DoubleEndedIterator<Item = Value> + '_ {
(0..self.len()).flat_map(|i| self.get(i))
}
}
Loading

0 comments on commit 11d7df0

Please sign in to comment.