Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/static.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ jobs:
- run: rustup update
- run: rustup toolchain install nightly
- run: rustup component add rust-src
- run: cargo doc --target=aarch64-nintendo-switch-freestanding --all-features
- run: cargo doc --target=aarch64-nintendo-switch-freestanding --all-features --no-deps
- run: mkdir docs
- run: cp .github/docs/index.html ./docs
- run: mv ./target/aarch64-nintendo-switch-freestanding/doc ./docs/doc
Expand Down
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ include = [

[dependencies]
paste = "1.0"
logpacket = { git = "https://github.com/aarch64-switch-rs/logpacket" }
logpacket = { git = "https://github.com/aarch64-switch-rs/logpacket", tag = "0.1.0"}
arrayvec = { version = "0.7.4", default-features = false }
static_assertions = "1.1.0"
lock_api = { version = "0.4.12", features = ["nightly"] }
Expand Down Expand Up @@ -76,8 +76,8 @@ default = []
services = []
smc = []
gpu = ["services"]
vty = ["console", "dep:embedded-term", "dep:embedded-graphics-core"]
console = ["canvas", "dep:font8x8"]
vty = ["canvas", "dep:embedded-term", "dep:embedded-graphics-core"]
console = ["fonts"]
canvas = ["gpu", "dep:line_drawing"]
fonts = ["canvas", "dep:ab_glyph", "dep:font8x8"]
truetype = ["fonts"]
Expand Down
12 changes: 1 addition & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,26 +57,16 @@

- NRO Romfs support

- Finish implementing all SVCs
- Finish implementing all SVC wrappers.

- Actual hw-rendering? (maybe as a separate lib like [deko3d](https://github.com/devkitPro/deko3d)?)

- Finish SMC support

- Finish waitable support

- Improve library applet support (specific implementations, etc.)

- Optimize IPC code to generate even better asm (like libnx or nnsdk)

- Finish documenting still-undocumented modules (`ipc`, `svc` and `service`)

- Console support

- `std` support

- (low priority) 32-bit support (see the corresponding branch)

## Credits

- [libnx](https://github.com/switchbrew/libnx) and its contributors for being the base of this project.
Expand Down
2 changes: 1 addition & 1 deletion nx-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "nx-derive"
version = "0.1.0"
edition = "2021"
edition = "2024"
publish = false

[lib]
Expand Down
89 changes: 50 additions & 39 deletions nx-derive/src/ipc_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use std::str::FromStr;
use proc_macro2::{Ident, Span, TokenStream};
use quote::{format_ident, quote};
use syn::{
AngleBracketedGenericArguments, AttrStyle, FnArg, GenericArgument, Path, PathSegment,
ReturnType, TraitItem, TraitItemFn, Type, TypePath,
punctuated::Punctuated,
spanned::Spanned,
token::{Gt, Lt, Mut, PathSep},
AngleBracketedGenericArguments, AttrStyle, FnArg, GenericArgument, Path, PathSegment,
ReturnType, TraitItem, TraitItemFn, Type, TypePath,
};

pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<TokenStream> {
Expand All @@ -19,25 +19,21 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
let client_trait = format_ident!("I{}Client", name);
let server_trait = format_ident!("I{}Server", name);

let build_default_client = input
.attrs
.iter()
.find(|&attr| {
if let syn::Attribute {
meta: syn::Meta::Path(p),
..
} = attr
{
p.is_ident("default_client")
} else {
false
}
})
.is_some();
let build_default_client = input.attrs.iter().any(|attr| {
if let syn::Attribute {
meta: syn::Meta::Path(p),
..
} = attr
{
p.is_ident("default_client")
} else {
false
}
});

let default_client: TokenStream = if build_default_client {
quote! {
/// The default client for the `#name` trait. All implementors of the trait need to read their session in accordance with this Types IPC Parameter traits.
#[doc = concat!("The default client for the `", stringify!(#name), "` trait. All implementors of the trait need to read their session in accordance with this Types IPC Parameter traits.")]
pub struct #name {
#[doc(hidden)]
pub (crate) session: ::nx::ipc::sf::Session
Expand Down Expand Up @@ -152,7 +148,10 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
} else if path.is_ident("version") {
version_req = Some(syn::parse2::<syn::Expr>(tokens.clone())?);
} else {
return Err(stringify_error(fn_item.span(), "Only the `ipc_rid`, `version`, `no_wrap_return`, and `return_session` attrs are supported on ipc trait functions (plus doc comments)"));
return Err(stringify_error(
fn_item.span(),
"Only the `ipc_rid`, `version`, `no_wrap_return`, and `return_session` attrs are supported on ipc trait functions (plus doc comments)",
));
}
} else if let syn::Attribute {
meta: syn::Meta::Path(p),
Expand All @@ -164,7 +163,10 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
} else if p.is_ident("no_wrap_return") {
return_wrap_result = false
} else {
return Err(stringify_error(fn_item.span(), "Only the `ipc_rid`, `version` `no_wrap_return`, and `return_session` attrs are supported on ipc trait functions (plus doc comments)"));
return Err(stringify_error(
fn_item.span(),
"Only the `ipc_rid`, `version` `no_wrap_return`, and `return_session` attrs are supported on ipc trait functions (plus doc comments)",
));
}
} else if let syn::Attribute {
style: AttrStyle::Outer,
Expand All @@ -175,7 +177,10 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
{
doc_comment = Some(attr.clone());
} else {
return Err(stringify_error(fn_item.span(), "Only the `ipc_rid`, `version` `no_wrap_return`, and `return_session` attrs are supported on ipc trait functions (plus doc comments)"));
return Err(stringify_error(
fn_item.span(),
"Only the `ipc_rid`, `version` `no_wrap_return`, and `return_session` attrs are supported on ipc trait functions (plus doc comments)",
));
}
}

Expand Down Expand Up @@ -206,7 +211,7 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
.inputs
.iter()
.skip(1)
.map(|fn_args| {
.try_for_each(|fn_args| {
let arg_span = fn_args.span();
let arg_pat = match fn_args {
FnArg::Typed(pat) => pat,
Expand All @@ -233,8 +238,7 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
in_param_types.push(arg_pat.ty.clone());

Ok(())
})
.collect::<Result<(), syn::Error>>()?;
})?;

let mut out_param_names = vec![];
let mut out_param_types = vec![];
Expand Down Expand Up @@ -266,9 +270,9 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
}
_ => {
return Err(stringify_error(
client_fn.sig.output.span(),
"Only tuple types, paren-wrapped types, or paths are supported for return types",
));
client_fn.sig.output.span(),
"Only tuple types, paren-wrapped types, or paths are supported for return types",
));
}
},
}
Expand Down Expand Up @@ -369,7 +373,10 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
&& let Type::Path(ty) = *bty
{
if ty.path.segments.len() != 1 {
return Err(stringify_error(server_fn.sig.output.span(), "Output type be a raw type name (the base name of the traits) the return type is marked as a session type"));
return Err(stringify_error(
server_fn.sig.output.span(),
"Output type be a raw type name (the base name of the traits) the return type is marked as a session type",
));
}
let out_type_ident = format!(
" -> impl I{}Server + 'static",
Expand All @@ -378,7 +385,10 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
server_fn.sig.output =
syn::parse2::<ReturnType>(FromStr::from_str(out_type_ident.as_str())?)?;
} else {
return Err(stringify_error(server_fn.sig.output.span(), "Output type be a raw type name (the base name of the traits) the return type is marked as a session type"));
return Err(stringify_error(
server_fn.sig.output.span(),
"Output type be a raw type name (the base name of the traits) the return type is marked as a session type",
));
}
}

Expand Down Expand Up @@ -490,17 +500,18 @@ pub fn ipc_trait(_args: TokenStream, ipc_trait: TokenStream) -> syn::Result<Toke
#server_fns
)*

/// The dynamic dispatch function that calls into the IPC server functions. This should only be called from the [`::nx::ipc::server::ServerManager`] and not from client code.
/// Examples for implementing [`ISessionObject`][`::nx::ipc::server::ISessionObject`] or [`IMitmServerOject`][`::nx::ipc::server::IMitmServerObject`] can be found in the [`nx`] crate.
fn try_handle_request_by_id(&mut self, req_id: u32, protocol: ::nx::ipc::CommandProtocol, ctx: &mut ::nx::ipc::server::ServerContext) -> Option<::nx::result::Result<()>> {
let version = ::nx::version::get_version();
match req_id {
#(
#handle_request_matches
),*
_ => None
}
/// The dynamic dispatch function that calls into the IPC server functions. This should only be called from the [`ServerManager`][`::nx::ipc::server::ServerManager`] and not from client code.
///
/// Examples for implementing [`ISessionObject`][`::nx::ipc::server::ISessionObject`] or [`IMitmServerOject`][`::nx::ipc::server::IMitmServerObject`] can be found in the [examples](https://github.com/aarch64-switch-rs/examples/) crate.
fn try_handle_request_by_id(&mut self, req_id: u32, protocol: ::nx::ipc::CommandProtocol, ctx: &mut ::nx::ipc::server::ServerContext) -> Option<::nx::result::Result<()>> {
let version = ::nx::version::get_version();
match req_id {
#(
#handle_request_matches
),*
_ => None
}
}
}
})
}
Expand Down
12 changes: 5 additions & 7 deletions nx-derive/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#![feature(let_chains)]

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput};
use syn::{DeriveInput, parse_macro_input};

mod ipc_traits;

Expand All @@ -13,7 +11,7 @@ pub fn derive_request(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);

let name = input.ident;
return TokenStream::from(quote!(
TokenStream::from(quote!(
impl ::nx::ipc::client::RequestCommandParameter for #name {
fn before_request_write(_raw: &Self, walker: &mut ::nx::ipc::DataWalker, ctx: &mut ::nx::ipc::CommandContext) -> ::nx::result::Result<()> {
walker.advance::<Self>();
Expand All @@ -31,7 +29,7 @@ pub fn derive_request(input: TokenStream) -> TokenStream {
Ok(ctx.raw_data_walker.advance_get())
}
}
));
))
}

/// This creates the required trait implementations for the type to be used as an IPC response parameter.
Expand All @@ -42,7 +40,7 @@ pub fn derive_response(input: TokenStream) -> TokenStream {

let name = input.ident;
let item_generics = &input.generics;
return TokenStream::from(quote!(
TokenStream::from(quote!(
impl #item_generics ::nx::ipc::client::ResponseCommandParameter<#name> for #name {
fn after_response_read(walker: &mut ::nx::ipc::DataWalker, ctx: &mut ::nx::ipc::CommandContext) -> ::nx::result::Result<Self> {
Ok(walker.advance_get())
Expand All @@ -60,7 +58,7 @@ pub fn derive_response(input: TokenStream) -> TokenStream {
Ok(())
}
}
));
))
}

#[proc_macro_attribute]
Expand Down
19 changes: 18 additions & 1 deletion src/applet.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
//! AppletAE/AppletOE Support

use crate::hbl::{AppletType, get_applet_type};
use crate::ipc::sf;
use crate::result::*;
Expand All @@ -14,13 +16,22 @@ static ALL_SYSTEM_APPLET_PROXY_SERVICE: RwLock<Option<AllSystemAppletProxiesServ
RwLock::new(None);
static LIBRARY_APPLET_PROXY: RwLock<Option<AppletProxy>> = RwLock::new(None);
static WINDOW_CONTROLLER: RwLock<Option<WindowController>> = RwLock::new(None);

/// Global AppletResourceUserID.
/// Stored as part of `applet::initialize()`
pub static GLOBAL_ARUID: AtomicU64 = AtomicU64::new(0);

/// Proxy type to avoid passing boxed trait objects for Applet Proxy actions.
pub enum AppletProxy {
/// AppletType::Application | AppletType::Default
Application(ApplicationProxy),
/// AppletType::SystemApplet
SystemApplet(SystemAppletProxy),
/// AppletType::LibraryApplet
LibraryApplet(LibraryAppletProxy),
/// AppletType::OverlayApplet
OverlayApplet(OverlayAppletProxy),
/// AppletType::SystemApplication
SystemApplication(SystemApplicationProxy),
}

Expand Down Expand Up @@ -65,7 +76,11 @@ impl ProxyCommon for AppletProxy {
}
}

/// global AppletAttribute used for openning the applet proxy for the program
///
/// TODO - make a better way to override this value
#[linkage = "weak"]
#[unsafe(export_name = "__nx_applet_attribute")]
pub static APPLET_ATTRIBUTE: AppletAttribute = AppletAttribute::zero();

/// Attempts to initialize the module, or returns if the module has already been initialized.
Expand Down Expand Up @@ -164,14 +179,16 @@ pub(crate) fn finalize() {
*app_proxy_service_guard = None;
}

/// Gets the registered global Window Controller
pub fn get_window_controller<'a>() -> ReadGuard<'a, Option<WindowController>> {
WINDOW_CONTROLLER.read()
}

/// Gets the registered global AppletProxy
pub fn get_applet_proxy<'a>() -> ReadGuard<'a, Option<AppletProxy>> {
LIBRARY_APPLET_PROXY.read()
}

/// Gets the registered global System Proxy Service
pub fn get_system_proxy_service<'a>() -> ReadGuard<'a, Option<AllSystemAppletProxiesService>> {
ALL_SYSTEM_APPLET_PROXY_SERVICE.read()
}
Loading