Compare commits
16 commits
v0
...
renovate/m
| Author | SHA1 | Date | |
|---|---|---|---|
| 78262f294d | |||
| 0b9d9ad214 | |||
| ca8315da8e | |||
| 3757658fd5 | |||
| 98e57710e1 | |||
| 741f02e59d | |||
| 13062a25b5 | |||
| 45355d3407 | |||
| 1e25661d81 | |||
| 3454164719 | |||
| 18f5ea93fc | |||
| f93168d60e | |||
| 9563c050c8 | |||
| ec66224b98 | |||
| af0b6d7a3b | |||
| 5d54d92e67 |
28 changed files with 1117 additions and 1633 deletions
|
|
@ -1,15 +1,20 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
export EDITION=$1
|
||||
export BA="--network=host --build-arg EDITION=$1 --build-arg DATABASE_URL="$DATABASE_URL""
|
||||
source /etc/environment
|
||||
: "${RNEX_CONTAINER_PLATFORM:=podman}"
|
||||
export BUILDKIT_PROGRESS=plain
|
||||
|
||||
for TARGET in node-holder proxy-secure proxy-insecure backend-auth backend-secure; do
|
||||
$RNEX_CONTAINER_PLATFORM build \
|
||||
--network=host \
|
||||
--build-arg EDITION="$EDITION" \
|
||||
--build-arg DATABASE_URL="$DATABASE_URL" \
|
||||
-t "$CI_REGISTRY_IMAGE/$EDITION/$TARGET:$CI_COMMIT_SHORT_SHA" \
|
||||
--target="$TARGET" .
|
||||
|
||||
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/$TARGET:$CI_COMMIT_SHORT_SHA"
|
||||
done
|
||||
# $RNEX_CONTAINER_PLATFORM build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest" --target=dev-container .
|
||||
# $RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/dev-container:latest"
|
||||
$RNEX_CONTAINER_PLATFORM build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA" --target=node-holder .
|
||||
$RNEX_CONTAINER_PLATFORM build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA" --target=proxy-secure .
|
||||
$RNEX_CONTAINER_PLATFORM build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA" --target=proxy-insecure .
|
||||
$RNEX_CONTAINER_PLATFORM build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA" --target=backend-auth .
|
||||
$RNEX_CONTAINER_PLATFORM build $BA -t "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA" --target=backend-secure .
|
||||
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/node-holder:$CI_COMMIT_SHORT_SHA"
|
||||
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/proxy-secure:$CI_COMMIT_SHORT_SHA"
|
||||
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/proxy-insecure:$CI_COMMIT_SHORT_SHA"
|
||||
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/backend-auth:$CI_COMMIT_SHORT_SHA"
|
||||
$RNEX_CONTAINER_PLATFORM push "$CI_REGISTRY_IMAGE/$EDITION/backend-secure:$CI_COMMIT_SHORT_SHA"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ name: Build and Test
|
|||
on:
|
||||
push:
|
||||
branches: ["**"]
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
DOCKER_TLS_CERTDIR: /certs
|
||||
|
|
@ -11,186 +10,6 @@ env:
|
|||
SHORT_SHA: ${{ github.sha }}
|
||||
|
||||
jobs:
|
||||
mario-tennis:
|
||||
runs-on: debian-trixie
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache container storage
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/lib/containers/storage
|
||||
/run/containers/storage
|
||||
~/.local/share/containers/storage
|
||||
key: image-cache
|
||||
|
||||
- name: Login to registry
|
||||
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||
|
||||
- name: Set short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build MTUS tetris edition
|
||||
env:
|
||||
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||
run: ./.ci-scripts/make-edition.sh mario-tennis
|
||||
|
||||
wii-sports-club:
|
||||
runs-on: debian-trixie
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache container storage
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/lib/containers/storage
|
||||
/run/containers/storage
|
||||
~/.local/share/containers/storage
|
||||
key: image-cache
|
||||
|
||||
- name: Login to registry
|
||||
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||
|
||||
- name: Set short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Wii Sports Club edition
|
||||
env:
|
||||
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||
run: ./.ci-scripts/make-edition.sh wii-sports-club
|
||||
|
||||
puyopuyo:
|
||||
runs-on: debian-trixie
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache container storage
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/lib/containers/storage
|
||||
/run/containers/storage
|
||||
~/.local/share/containers/storage
|
||||
key: image-cache
|
||||
|
||||
- name: Login to registry
|
||||
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||
|
||||
- name: Set short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build puyo puyo tetris edition
|
||||
env:
|
||||
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||
run: ./.ci-scripts/make-edition.sh puyopuyo
|
||||
|
||||
minecraft-wiiu:
|
||||
runs-on: debian-trixie
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache container storage
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/lib/containers/storage
|
||||
/run/containers/storage
|
||||
~/.local/share/containers/storage
|
||||
key: image-cache
|
||||
|
||||
- name: Login to registry
|
||||
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||
|
||||
- name: Set short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Minecraft Wii U edition
|
||||
env:
|
||||
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||
run: ./.ci-scripts/make-edition.sh minecraft-wiiu
|
||||
|
||||
splatoon-testfire:
|
||||
runs-on: debian-trixie
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache container storage
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/lib/containers/storage
|
||||
/run/containers/storage
|
||||
~/.local/share/containers/storage
|
||||
key: image-cache
|
||||
|
||||
- name: Login to registry
|
||||
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||
|
||||
- name: Set short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Splatoon Testfire edition
|
||||
env:
|
||||
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||
run: ./.ci-scripts/make-edition.sh splatoon-testfire
|
||||
|
||||
fast-racing-neo:
|
||||
runs-on: debian-trixie
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Cache container storage
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
/var/lib/containers/storage
|
||||
/run/containers/storage
|
||||
~/.local/share/containers/storage
|
||||
key: image-cache
|
||||
|
||||
- name: Login to registry
|
||||
run: docker login -u ${{ secrets.PACKAGE_USER }} -p ${{ secrets.PACKAGE_PWD }} git.spbr.net
|
||||
|
||||
- name: Set short SHA
|
||||
run: echo "SHORT_SHA=${GITHUB_SHA::6}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build Fast Racing NEO edition
|
||||
env:
|
||||
CI_REGISTRY_IMAGE: git.spbr.net/spacebar/rust-nex
|
||||
CI_COMMIT_SHORT_SHA: ${{ env.SHORT_SHA }}
|
||||
run: ./.ci-scripts/make-edition.sh fast-racing-neo
|
||||
|
||||
wii-u-chat:
|
||||
runs-on: debian-trixie
|
||||
|
||||
|
|
|
|||
533
Cargo.lock
generated
533
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
52
Dockerfile
52
Dockerfile
|
|
@ -1,57 +1,43 @@
|
|||
# syntax=docker/dockerfile:1
|
||||
FROM rust:alpine AS chef
|
||||
RUN apk add --no-cache musl-dev lld g++ make
|
||||
RUN cargo install cargo-chef
|
||||
FROM rust:alpine AS build-container
|
||||
|
||||
RUN apk add --no-cache protobuf-dev git musl-dev lld openssl-dev openssl-libs-static yq bash
|
||||
|
||||
FROM build-container AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
FROM chef AS planner
|
||||
COPY . .
|
||||
RUN cargo chef prepare --recipe-path recipe.json
|
||||
|
||||
FROM chef AS builder
|
||||
RUN apk add --no-cache protobuf-dev git openssl-dev openssl-libs-static bash yq
|
||||
|
||||
COPY --from=planner /app/recipe.json recipe.json
|
||||
ARG EDITION
|
||||
ARG DATABASE_URL
|
||||
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/app/target \
|
||||
cargo chef cook --release --recipe-path recipe.json --target x86_64-unknown-linux-musl && \
|
||||
cargo chef cook --tests --target x86_64-unknown-linux-musl --recipe-path recipe.json
|
||||
|
||||
COPY . .
|
||||
RUN --mount=type=cache,target=/usr/local/cargo/registry \
|
||||
--mount=type=cache,target=/app/target \
|
||||
./test-edition.sh && ./build-edition.sh && \
|
||||
mkdir -p /app/dist && \
|
||||
cp /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /app/dist/ && \
|
||||
cp /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /app/dist/ && \
|
||||
cp /app/target/x86_64-unknown-linux-musl/release/proxy_secure /app/dist/ && \
|
||||
cp /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /app/dist/ && \
|
||||
cp /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /app/dist/
|
||||
RUN git submodule update --init --recursive
|
||||
|
||||
RUN ./test-edition.sh
|
||||
RUN ./build-edition.sh
|
||||
|
||||
FROM scratch AS node-holder
|
||||
COPY --from=builder /app/dist/edge_node_holder_server /edge_node_holder_server
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/edge_node_holder_server /edge_node_holder_server
|
||||
ENTRYPOINT ["/edge_node_holder_server"]
|
||||
|
||||
|
||||
FROM scratch AS proxy-insecure
|
||||
COPY --from=builder /app/dist/proxy_insecure /proxy_insecure
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_insecure /proxy_insecure
|
||||
ENTRYPOINT ["/proxy_insecure"]
|
||||
|
||||
FROM scratch AS proxy-secure
|
||||
COPY --from=builder /app/dist/proxy_secure /proxy_secure
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/proxy_secure /proxy_secure
|
||||
ENTRYPOINT ["/proxy_secure"]
|
||||
|
||||
|
||||
FROM scratch AS backend-auth
|
||||
COPY --from=builder /app/dist/backend_server_insecure /backend_server_insecure
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_insecure /backend_server_insecure
|
||||
ENTRYPOINT ["/backend_server_insecure"]
|
||||
|
||||
FROM scratch AS backend-secure
|
||||
COPY --from=builder /app/dist/backend_server_secure /backend_server_secure
|
||||
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/backend_server_secure /backend_server_secure
|
||||
ENTRYPOINT ["/backend_server_secure"]
|
||||
|
||||
FROM chef AS dev-container
|
||||
RUN apk add --no-cache openjdk21-jdk gcompat git bash protobuf-dev
|
||||
COPY --from=builder /app/dist/* /usr/local/bin/
|
||||
# make sure the final output container is the dev container so that we can use it from the devcontainer.json
|
||||
FROM build-container AS dev-container
|
||||
RUN apk add openjdk21-jdk gcompat
|
||||
|
|
|
|||
22
README.md
22
README.md
|
|
@ -1,16 +1,20 @@
|
|||
# Rust NEX monorepo
|
||||
|
||||
This repo contains the code for all game servers using RNEX.
|
||||
# Splatoon NEX Server in Rust
|
||||
|
||||
## Credits:
|
||||
- Pretendo team for their reverse engineering efforts
|
||||
- Pretendo team for the rest of the Servers and Reverse engineering efforts
|
||||
- Kinnay for his huge work on reversing nex servers and documentation(https://github.com/Kinnay/NintendoClients/)
|
||||
- Splatfestival testing team for helping us test our messes of code
|
||||
- The SPFN team(RusticMaple, BloxerHD, Ceantix, RedBinder0526)
|
||||
- The SPFN team(Bloxer, Ceantix and RusticMaple)
|
||||
|
||||
This NEX implementation was not created to rival Pretendo, we don't want any bad blood between anyone.
|
||||
This nex implementation was not created and is not intended to compete with pretendo,
|
||||
we wholeheartedly support pretendo.
|
||||
This project would never have been possible without their reverse engineering efforts.
|
||||
As such if you want to respect the Authors wishes, do not use it if you mean any harm to Pretendo. (harm falls under e.g. using this software while also sabotaging pretendo) If you do show intent to harm them you will be blocked from ever contributing and will be refused support.
|
||||
As such if you want to respect the Authors wishes(Maple(Me) is pretty much the sole author of Rust-Nex), do not
|
||||
use it if you mean any harm to pretendo. If you do show intent to harm them you will be blocked from ever contributing
|
||||
and will be refused support, as such please also refrain from asking for support if you have been blocked by pretendo.
|
||||
|
||||
We felt like this needed to be said as there are far too many Pretendo copycats who blatantly copy their code and use their reversal efforts with no credits in sight in an attempt to harm them for some grudge or stupid reason.
|
||||
We feel that by working together and not against each other we can reach a better and healthier future for the community, health of developers and numerous more reasons.
|
||||
|
||||
I felt like this needed to be said as there are far too many pretendo copycats who blatantly copy their code and use
|
||||
their reversal efforts with no credits in sight in an attempt to harm them for some grudge or stupid reason.
|
||||
I feel that by working together and not against each other we can reach a better and healthier future for the community,
|
||||
health of developers and numerous more reasons.
|
||||
|
|
|
|||
|
|
@ -1,51 +1,3 @@
|
|||
wii-sports-club:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- third-notif-param
|
||||
- v3-8-15
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/project/appsp build:3_4_24_4_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 10000
|
||||
RNEX_ACCESS_KEY: "4d324052"
|
||||
puyopuyo:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- third-notif-param
|
||||
- v3-8-15
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.5.x.1000 build:3_5_16_1000_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 10000
|
||||
RNEX_ACCESS_KEY: "4eb0ca36"
|
||||
minecraft-wiiu:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- third-notif-param
|
||||
- v3-10-22
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.10.x.200x build:3_10_22_2006_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 13000
|
||||
RNEX_ACCESS_KEY: "f1b61c8e"
|
||||
mario-tennis:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- third-notif-param
|
||||
- v3-8-15
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.9.x.200x build:3_9_19_2005_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 10000
|
||||
RNEX_ACCESS_KEY: "c69b92a0"
|
||||
wii-u-chat:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
|
|
@ -58,41 +10,17 @@ wii-u-chat:
|
|||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 10000
|
||||
RNEX_ACCESS_KEY: "e7a47214"
|
||||
fast-racing-neo:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- v3-8-15
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/release/ngs/3.9.x.200x build:3_9_19_2005_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 10000
|
||||
RNEX_ACCESS_KEY: "811aa39f"
|
||||
splatoon:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- v3-8-15
|
||||
- splatoon
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 6000
|
||||
RNEX_ACCESS_KEY: "6f599f81"
|
||||
splatoon-testfire:
|
||||
include-in-checkall: true
|
||||
features:
|
||||
- prudpv1
|
||||
- v3-8-15
|
||||
- splatoon
|
||||
settings:
|
||||
AUTH_REPORT_VERSION: "branch:origin/project/wup-agmj build:3_8_15_2004_0"
|
||||
RNEX_VIRTUAL_PORT_INSECURE: "1:10"
|
||||
RNEX_VIRTUAL_PORT_SECURE: "1:10"
|
||||
RNEX_DEFAULT_PORT: 10000
|
||||
RNEX_ACCESS_KEY: "da693ee5"
|
||||
friends:
|
||||
include-in-checkall: false
|
||||
features:
|
||||
|
|
|
|||
|
|
@ -1,27 +1,400 @@
|
|||
#![allow(dead_code)]
|
||||
mod protos;
|
||||
mod rmc_struct;
|
||||
mod util;
|
||||
|
||||
extern crate proc_macro;
|
||||
|
||||
use crate::protos::{ProtoInputParams, RmcProtocolData};
|
||||
use crate::rmc_struct::{rmc_serialize_enum, rmc_serialize_struct};
|
||||
use crate::protos::{ProtoMethodData, RmcProtocolData};
|
||||
use proc_macro::TokenStream;
|
||||
use proc_macro2::Ident;
|
||||
use quote::quote;
|
||||
use proc_macro2::{Ident, Literal, Span};
|
||||
use quote::{quote, TokenStreamExt};
|
||||
use syn::parse::{Parse, ParseStream};
|
||||
use syn::punctuated::Punctuated;
|
||||
use syn::spanned::Spanned;
|
||||
use syn::{parse_macro_input, Data, DeriveInput, Lit, LitStr};
|
||||
use syn::{
|
||||
parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, Lit, LitInt,
|
||||
LitStr, Pat, Token, TraitItem,
|
||||
};
|
||||
|
||||
struct ProtoInputParams {
|
||||
proto_num: LitInt,
|
||||
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>,
|
||||
}
|
||||
|
||||
impl Parse for ProtoInputParams {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let proto_num = input.parse()?;
|
||||
|
||||
if let Some(seperator) = input.parse()? {
|
||||
let mut punctuated = Punctuated::new();
|
||||
loop {
|
||||
punctuated.push_value(input.parse()?);
|
||||
if let Some(punct) = input.parse()? {
|
||||
punctuated.push_punct(punct);
|
||||
} else {
|
||||
return Ok(Self {
|
||||
proto_num,
|
||||
properties: Some((seperator, punctuated)),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(Self {
|
||||
proto_num,
|
||||
properties: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_serialize_data_struct(
|
||||
s: DataStruct,
|
||||
struct_attr: Option<&Attribute>,
|
||||
) -> (
|
||||
proc_macro2::TokenStream,
|
||||
proc_macro2::TokenStream,
|
||||
proc_macro2::TokenStream,
|
||||
) {
|
||||
let serialize_base_content = {
|
||||
let mut serialize_content = quote! {};
|
||||
|
||||
for f in &s.fields {
|
||||
if f.attrs.iter().any(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
|
||||
serialize_content.append_all(quote! {
|
||||
rnex_core::rmc::structures::RmcSerialize::serialize(&self.#ident, writer)?;
|
||||
})
|
||||
}
|
||||
|
||||
quote! {
|
||||
#serialize_content
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
|
||||
let struct_ctor = {
|
||||
let mut structure_content = quote! {};
|
||||
for f in &s.fields {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
|
||||
structure_content.append_all(quote! {#ident, });
|
||||
}
|
||||
|
||||
quote! {
|
||||
Ok(Self{
|
||||
#structure_content
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let deserialize_base_content = {
|
||||
let mut deserialize_content = quote! {};
|
||||
|
||||
for f in &s.fields {
|
||||
if f.attrs.iter().any(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||
}) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
let ty = &f.ty;
|
||||
|
||||
deserialize_content.append_all(quote! {
|
||||
let #ident = <#ty> :: deserialize(reader)?;
|
||||
})
|
||||
}
|
||||
|
||||
quote! {
|
||||
#deserialize_content
|
||||
#struct_ctor
|
||||
}
|
||||
};
|
||||
|
||||
let write_size = {
|
||||
let mut size_content = quote! { 0 };
|
||||
|
||||
for f in &s.fields {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
|
||||
size_content.append_all(quote! {
|
||||
+ rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)?
|
||||
})
|
||||
}
|
||||
|
||||
size_content
|
||||
};
|
||||
let write_size = if let Some(_) = struct_attr {
|
||||
quote! { #write_size + if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 } }
|
||||
} else {
|
||||
write_size
|
||||
};
|
||||
|
||||
// generate base with extends stuff
|
||||
|
||||
let serialize_base_content = if let Some(attr) = struct_attr {
|
||||
let version: Literal = attr.parse_args().expect("has to be a literal");
|
||||
|
||||
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
||||
f.attrs.iter().any(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||
})
|
||||
}) {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
quote! {
|
||||
self.#ident.serialize(writer)?;
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#pre_inner
|
||||
rnex_core::rmc::structures::rmc_struct::write_struct(
|
||||
writer,
|
||||
#version,
|
||||
rnex_core::rmc::structures::helpers::len_of_write(
|
||||
|writer|{
|
||||
#serialize_base_content
|
||||
}
|
||||
),
|
||||
|writer|{
|
||||
#serialize_base_content
|
||||
}
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
serialize_base_content
|
||||
};
|
||||
|
||||
let deserialize_base_content = if let Some(attr) = struct_attr {
|
||||
let version: Literal = attr.parse_args().expect("has to be a literal");
|
||||
|
||||
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
||||
f.attrs.iter().any(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||
})
|
||||
}) {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
let ty = &f.ty;
|
||||
quote! {
|
||||
let #ident = <#ty> :: deserialize(reader)?;
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#pre_inner
|
||||
Ok(rnex_core::rmc::structures::rmc_struct::read_struct(reader, #version, move |mut reader|{
|
||||
#deserialize_base_content
|
||||
})?)
|
||||
}
|
||||
} else {
|
||||
deserialize_base_content
|
||||
};
|
||||
|
||||
let write_size = quote! {
|
||||
fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result<u32>{
|
||||
Ok(#write_size)
|
||||
}
|
||||
};
|
||||
|
||||
(serialize_base_content, deserialize_base_content, write_size)
|
||||
}
|
||||
|
||||
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
|
||||
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||
let derive_input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
let (serialize, deserialize, write_size, version) = match &derive_input.data {
|
||||
Data::Struct(s) => rmc_serialize_struct(s, &derive_input),
|
||||
Data::Enum(e) => rmc_serialize_enum(e, &derive_input),
|
||||
let struct_attr = derive_input.attrs.iter().find(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "rmc_struct")
|
||||
});
|
||||
let repr_attr = derive_input.attrs.iter().find(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "repr")
|
||||
});
|
||||
|
||||
/*let Data::Struct(s) = derive_input.data else {
|
||||
panic!("rmc struct type MUST be a struct");
|
||||
};*/
|
||||
|
||||
let (serialize_base_content, deserialize_base_content, write_size) = match derive_input.data {
|
||||
Data::Struct(s) => gen_serialize_data_struct(s, struct_attr),
|
||||
Data::Enum(e) => {
|
||||
let Some(repr_attr) = repr_attr else {
|
||||
panic!("missing repr attribute");
|
||||
};
|
||||
|
||||
let ty: Ident = repr_attr.parse_args().unwrap();
|
||||
|
||||
let mut inner_match_de = quote! {};
|
||||
let mut inner_match_se = quote! {};
|
||||
//let mut inner_match_len = quote!{};
|
||||
|
||||
for variant in e.variants {
|
||||
let Some((_, val)) = variant.discriminant else {
|
||||
panic!("missing discriminant");
|
||||
};
|
||||
|
||||
let field_data_de = match &variant.fields {
|
||||
Fields::Named(v) => {
|
||||
let mut base = quote! {};
|
||||
for field in v.named.iter() {
|
||||
let ty = &field.ty;
|
||||
let name = &field.ident;
|
||||
|
||||
base.append_all(quote!{
|
||||
#name: <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?,
|
||||
});
|
||||
}
|
||||
|
||||
quote! {{#base}}
|
||||
}
|
||||
Fields::Unnamed(n) => {
|
||||
let mut base = quote! {};
|
||||
|
||||
for field in n.unnamed.iter() {
|
||||
let ty = &field.ty;
|
||||
|
||||
base.append_all(quote!{
|
||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?,
|
||||
});
|
||||
}
|
||||
|
||||
quote! {(#base)}
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote! {}
|
||||
}
|
||||
};
|
||||
|
||||
let mut se_with_fields = quote! {
|
||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(&#val, writer)?;
|
||||
};
|
||||
|
||||
match &variant.fields {
|
||||
Fields::Named(v) => {
|
||||
for field in v.named.iter() {
|
||||
let ty = &field.ty;
|
||||
let name = &field.ident;
|
||||
|
||||
se_with_fields.append_all(quote!{
|
||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#name ,writer)?;
|
||||
});
|
||||
}
|
||||
}
|
||||
Fields::Unnamed(n) => {
|
||||
for (i, field) in n.unnamed.iter().enumerate() {
|
||||
let ty = &field.ty;
|
||||
|
||||
let ident = Ident::new(&format!("val_{}", i), Span::call_site());
|
||||
|
||||
se_with_fields.append_all(quote!{
|
||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#ident, writer)?;
|
||||
});
|
||||
}
|
||||
}
|
||||
Fields::Unit => {}
|
||||
};
|
||||
|
||||
let field_match_se = match &variant.fields {
|
||||
Fields::Named(v) => {
|
||||
let mut base = quote! {};
|
||||
|
||||
for field in v.named.iter() {
|
||||
let name = &field.ident;
|
||||
|
||||
base.append_all(quote! {
|
||||
#name,
|
||||
});
|
||||
}
|
||||
|
||||
quote! {{#base}}
|
||||
}
|
||||
Fields::Unnamed(n) => {
|
||||
let mut base = quote! {};
|
||||
|
||||
for (i, _field) in n.unnamed.iter().enumerate() {
|
||||
let ident = Ident::new(&format!("val_{}", i), Span::call_site());
|
||||
|
||||
base.append_all(quote! {
|
||||
#ident,
|
||||
});
|
||||
}
|
||||
|
||||
quote! {(#base)}
|
||||
}
|
||||
Fields::Unit => {
|
||||
quote! {}
|
||||
}
|
||||
};
|
||||
|
||||
let name = variant.ident;
|
||||
|
||||
inner_match_de.append_all(quote! {
|
||||
#val => Self::#name #field_data_de,
|
||||
});
|
||||
|
||||
inner_match_se.append_all(quote! {
|
||||
Self::#name #field_match_se => {
|
||||
#se_with_fields
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
let serialize_base_content = quote! {
|
||||
match self{
|
||||
#inner_match_se
|
||||
};
|
||||
|
||||
|
||||
|
||||
Ok(())
|
||||
};
|
||||
|
||||
let deserialize_base_content = quote! {
|
||||
let val: Self = match <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?{
|
||||
#inner_match_de
|
||||
v => return Err(rnex_core::rmc::structures::Error::UnexpectedValue(v as _))
|
||||
};
|
||||
|
||||
Ok(val)
|
||||
};
|
||||
|
||||
(serialize_base_content, deserialize_base_content, quote! {})
|
||||
}
|
||||
Data::Union(_) => {
|
||||
unimplemented!("serialize a union is not allowed");
|
||||
unimplemented!()
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -33,41 +406,19 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
|||
));
|
||||
let ident = derive_input.ident;
|
||||
|
||||
let write_size = if let Some(v) = write_size {
|
||||
quote! {
|
||||
fn serialize_write_size(&self) -> rnex_core::rmc::structures::Result<u32>{
|
||||
#v
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let version = if let Some(v) = version {
|
||||
quote! {
|
||||
fn version() -> Option<u8>{
|
||||
#v
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let tokens = quote! {
|
||||
impl rnex_core::rmc::structures::RmcSerialize for #ident{
|
||||
#[inline(always)]
|
||||
fn serialize(&self, writer: &mut impl ::std::io::Write) -> rnex_core::rmc::structures::Result<()>{
|
||||
#serialize
|
||||
#serialize_base_content
|
||||
}
|
||||
#[inline(always)]
|
||||
fn deserialize(reader: &mut impl ::std::io::Read) -> rnex_core::rmc::structures::Result<Self>{
|
||||
#deserialize
|
||||
#deserialize_base_content
|
||||
}
|
||||
|
||||
#write_size
|
||||
|
||||
#version
|
||||
|
||||
fn name() -> &'static str{
|
||||
#str_name
|
||||
}
|
||||
|
|
@ -104,9 +455,71 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
|||
#[proc_macro_attribute]
|
||||
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream {
|
||||
let params = parse_macro_input!(attr as ProtoInputParams);
|
||||
|
||||
let ProtoInputParams {
|
||||
proto_num,
|
||||
properties,
|
||||
} = params;
|
||||
|
||||
let no_return_data =
|
||||
properties.is_some_and(|p| p.1.iter().any(|i| i.to_string() == "NoReturn"));
|
||||
|
||||
let input = parse_macro_input!(input as syn::ItemTrait);
|
||||
|
||||
let raw_data = RmcProtocolData::new(params, &input);
|
||||
// gigantic ass struct initializer (to summarize this gets all of the data)
|
||||
let raw_data = RmcProtocolData {
|
||||
has_returns: !no_return_data,
|
||||
name: input.ident.clone(),
|
||||
id: proto_num,
|
||||
methods: input
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(|v| match v {
|
||||
TraitItem::Fn(v) => Some(v),
|
||||
_ => None,
|
||||
})
|
||||
.map(|func| {
|
||||
let Some(attr) = func.attrs.iter().find(|a| {
|
||||
a.path()
|
||||
.segments
|
||||
.last()
|
||||
.is_some_and(|s| s.ident.to_string() == "method_id")
|
||||
}) else {
|
||||
panic!("every function inside of an rmc protocol must have a method id");
|
||||
};
|
||||
|
||||
let Ok(id): Result<LitInt, _> = attr.parse_args() else {
|
||||
panic!("todo: put a propper error message here");
|
||||
};
|
||||
|
||||
let funcs = func
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|f| {
|
||||
let FnArg::Typed(t) = f else {
|
||||
panic!("what");
|
||||
};
|
||||
let Pat::Ident(i) = &*t.pat else {
|
||||
panic!(
|
||||
"unable to handle non identifier patterns as parameter bindings"
|
||||
);
|
||||
};
|
||||
|
||||
(i.ident.clone(), t.ty.as_ref().clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
ProtoMethodData {
|
||||
id,
|
||||
name: func.sig.ident.clone(),
|
||||
parameters: funcs,
|
||||
ret_val: func.sig.output.clone(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
};
|
||||
|
||||
quote! {
|
||||
#input
|
||||
|
|
|
|||
|
|
@ -1,48 +1,12 @@
|
|||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use quote::{quote, ToTokens};
|
||||
use syn::{
|
||||
parse::{Parse, ParseStream},
|
||||
punctuated::Punctuated,
|
||||
Attribute, FnArg, ItemTrait, LitInt, LitStr, Meta, Pat, ReturnType, Token, TraitItem, Type,
|
||||
};
|
||||
use syn::token::{Brace, Paren, Semi};
|
||||
use syn::{LitInt, LitStr, ReturnType, Type};
|
||||
|
||||
use crate::util::fold_tokenable;
|
||||
|
||||
pub struct ProtoInputParams {
|
||||
proto_num: LitInt,
|
||||
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>,
|
||||
}
|
||||
|
||||
impl Parse for ProtoInputParams {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let proto_num = input.parse()?;
|
||||
|
||||
if let Some(seperator) = input.parse()? {
|
||||
let mut punctuated = Punctuated::new();
|
||||
loop {
|
||||
punctuated.push_value(input.parse()?);
|
||||
if let Some(punct) = input.parse()? {
|
||||
punctuated.push_punct(punct);
|
||||
} else {
|
||||
return Ok(Self {
|
||||
proto_num,
|
||||
properties: Some((seperator, punctuated)),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(Self {
|
||||
proto_num,
|
||||
properties: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
pub struct ProtoMethodData {
|
||||
pub id: LitInt,
|
||||
pub name: Ident,
|
||||
pub attributes: Vec<Attribute>,
|
||||
pub parameters: Vec<(Ident, Type, Vec<Attribute>)>,
|
||||
pub parameters: Vec<(Ident, Type)>,
|
||||
pub ret_val: ReturnType,
|
||||
}
|
||||
|
||||
|
|
@ -59,222 +23,108 @@ pub struct RmcProtocolData {
|
|||
}
|
||||
|
||||
impl RmcProtocolData {
|
||||
pub fn new(params: ProtoInputParams, input: &ItemTrait) -> Self {
|
||||
let ProtoInputParams {
|
||||
proto_num,
|
||||
properties,
|
||||
} = params;
|
||||
|
||||
let no_return_data =
|
||||
properties.is_some_and(|p| p.1.iter().any(|i| i.to_string() == "NoReturn"));
|
||||
|
||||
// gigantic ass struct initializer (to summarize this gets all of the data)
|
||||
RmcProtocolData {
|
||||
has_returns: !no_return_data,
|
||||
name: input.ident.clone(),
|
||||
id: proto_num,
|
||||
methods: input
|
||||
.items
|
||||
.iter()
|
||||
.filter_map(|v| match v {
|
||||
TraitItem::Fn(v) => Some(v),
|
||||
_ => None,
|
||||
})
|
||||
.map(|func| {
|
||||
let Some(attr) = func.attrs.iter().find(|a| {
|
||||
a.path()
|
||||
.segments
|
||||
.last()
|
||||
.is_some_and(|s| s.ident.to_string() == "method_id")
|
||||
}) else {
|
||||
panic!("every function inside of an rmc protocol must have a method id");
|
||||
};
|
||||
|
||||
let Ok(id): Result<LitInt, _> = attr.parse_args() else {
|
||||
panic!("todo: put a propper error message here");
|
||||
};
|
||||
|
||||
let funcs = func
|
||||
.sig
|
||||
.inputs
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|f| {
|
||||
let FnArg::Typed(t) = f else {
|
||||
panic!("what");
|
||||
};
|
||||
let Pat::Ident(i) = &*t.pat else {
|
||||
panic!(
|
||||
"unable to handle non identifier patterns as parameter bindings"
|
||||
);
|
||||
};
|
||||
|
||||
(i.ident.clone(), t.ty.as_ref().clone(), t.attrs.clone())
|
||||
})
|
||||
.collect();
|
||||
|
||||
ProtoMethodData {
|
||||
id,
|
||||
name: func.sig.ident.clone(),
|
||||
parameters: funcs,
|
||||
ret_val: func.sig.output.clone(),
|
||||
attributes: func
|
||||
.attrs
|
||||
.iter()
|
||||
.filter(|a| match &a.meta {
|
||||
Meta::NameValue(v) => {
|
||||
if let Some(i) = v.path.get_ident() {
|
||||
i.to_string() != "doc"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
Meta::List(l) => {
|
||||
if let Some(seg) = l.path.segments.last() {
|
||||
seg.ident.to_string() != "method_id"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
_ => true,
|
||||
})
|
||||
.cloned()
|
||||
.collect(),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_raw_trait(&self) -> TokenStream {
|
||||
fn generate_raw_trait(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
has_returns,
|
||||
name,
|
||||
id,
|
||||
methods,
|
||||
} = self;
|
||||
let generate_raw_method = |method: &ProtoMethodData| -> TokenStream {
|
||||
let ProtoMethodData {
|
||||
name,
|
||||
parameters,
|
||||
attributes,
|
||||
..
|
||||
} = method;
|
||||
|
||||
let attribs = fold_tokenable(attributes.iter());
|
||||
// this gives us the name which the identifier of the corresponding Raw trait
|
||||
let raw_name = Ident::new(&format!("Raw{}", name), name.span());
|
||||
|
||||
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||
// boilerplate tokens which all raw traits need
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_must_use)]
|
||||
pub trait #raw_name: #name
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
|
||||
let optional_return = if self.has_returns {
|
||||
quote! {
|
||||
-> ::core::result::Result<Vec<u8>, ::rnex_core::rmc::response::ErrorCode>
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
}
|
||||
.into_token_stream();
|
||||
|
||||
let deser_params =
|
||||
fold_tokenable(parameters.iter().map(|(param_name, param_type, attribs)| {
|
||||
let error_msg = LitStr::new(
|
||||
&format!("an error occurred whilest deserializing {}", param_name),
|
||||
Span::call_site(),
|
||||
);
|
||||
let return_from_deser_error = if self.has_returns {
|
||||
quote! {
|
||||
return Err(::rnex_core::rmc::response::ErrorCode::Core_InvalidArgument);
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
return;
|
||||
}
|
||||
};
|
||||
let attribs = fold_tokenable(attribs.iter());
|
||||
quote! {
|
||||
#attribs
|
||||
let Ok(#param_name) =
|
||||
<#param_type as rnex_core::rmc::structures::RmcSerialize>::deserialize(
|
||||
&mut cursor
|
||||
) else{
|
||||
log::error!(#error_msg);
|
||||
#return_from_deser_error
|
||||
};
|
||||
}
|
||||
}));
|
||||
|
||||
let call_params = fold_tokenable(parameters.iter().map(|(param_name, _, attribs)| {
|
||||
let attribs = fold_tokenable(attribs.iter());
|
||||
quote! {
|
||||
#attribs
|
||||
#param_name,
|
||||
}
|
||||
}));
|
||||
|
||||
let optional_method_return = if *has_returns {
|
||||
quote! {
|
||||
let retval = retval?;
|
||||
let mut vec = Vec::new();
|
||||
rnex_core::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok();
|
||||
Ok(vec)
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
#attribs
|
||||
async fn #raw_name (&self, data: ::std::vec::Vec<u8>) #optional_return{
|
||||
let mut cursor = ::std::io::Cursor::new(data);
|
||||
#deser_params
|
||||
let retval = self.#name(#call_params).await;
|
||||
#optional_method_return
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
let generate_rmc_call_proto = || {
|
||||
let method_entries = fold_tokenable(methods.iter().map(|m| {
|
||||
// generate the body of the raw protocol trait
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
//generate each raw method
|
||||
for method in methods{
|
||||
let ProtoMethodData {
|
||||
id,
|
||||
name,
|
||||
attributes,
|
||||
parameters,
|
||||
..
|
||||
} = m;
|
||||
} = method;
|
||||
|
||||
let attribs = fold_tokenable(attributes.iter());
|
||||
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||
quote!{
|
||||
#[inline(always)]
|
||||
async fn #raw_name
|
||||
}.to_tokens(tokens);
|
||||
|
||||
quote! {
|
||||
#attribs
|
||||
#id => self.#raw_name(data).await,
|
||||
Paren::default().surround(tokens, |tokens|{
|
||||
quote!{ &self, data: ::std::vec::Vec<u8> }.to_tokens(tokens);
|
||||
});
|
||||
|
||||
if self.has_returns {
|
||||
quote! {
|
||||
-> ::core::result::Result<Vec<u8>, ErrorCode>
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
}));
|
||||
|
||||
let optional_notimpl_return = if self.has_returns {
|
||||
quote! {
|
||||
Err(rnex_core::rmc::response::ErrorCode::Core_NotImplemented)
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
quote! { let mut cursor = ::std::io::Cursor::new(data); }.to_tokens(tokens);
|
||||
|
||||
let optional_result_sendback = if *has_returns {
|
||||
quote! {
|
||||
rnex_core::rmc::response::send_result(
|
||||
remote_response_connection,
|
||||
ret,
|
||||
#id,
|
||||
method_id,
|
||||
call_id,
|
||||
).await
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
for (param_name, param_type) in parameters{
|
||||
quote!{
|
||||
let Ok(#param_name) =
|
||||
<#param_type as rnex_core::rmc::structures::RmcSerialize>::deserialize(
|
||||
&mut cursor
|
||||
) else
|
||||
}.to_tokens(tokens);
|
||||
|
||||
quote! {
|
||||
let error_msg = LitStr::new(&format!("an error occurred whilest deserializing {}", param_name), Span::call_site());
|
||||
|
||||
if self.has_returns {
|
||||
quote! {
|
||||
{
|
||||
log::error!(#error_msg);
|
||||
return Err(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument);
|
||||
};
|
||||
}.to_tokens(tokens)
|
||||
} else {
|
||||
quote! {
|
||||
{
|
||||
log::error!(#error_msg);
|
||||
return;
|
||||
};
|
||||
}.to_tokens(tokens)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
quote!{
|
||||
let retval = self.#name
|
||||
}.to_tokens(tokens);
|
||||
|
||||
Paren::default().surround(tokens, |tokens|{
|
||||
for (paren_name, _) in parameters{
|
||||
quote!{#paren_name,}.to_tokens(tokens);
|
||||
}
|
||||
});
|
||||
|
||||
quote!{
|
||||
.await;
|
||||
}.to_tokens(tokens);
|
||||
|
||||
if *has_returns{
|
||||
quote!{
|
||||
let retval = retval?;
|
||||
let mut vec = Vec::new();
|
||||
rnex_core::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok();
|
||||
Ok(vec)
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
quote!{
|
||||
#[inline(always)]
|
||||
async fn rmc_call_proto(
|
||||
&self,
|
||||
|
|
@ -282,38 +132,71 @@ impl RmcProtocolData {
|
|||
method_id: u32,
|
||||
call_id: u32,
|
||||
data: Vec<u8>,
|
||||
){
|
||||
let ret = match method_id{
|
||||
#method_entries
|
||||
v => {
|
||||
)
|
||||
}.to_tokens(tokens);
|
||||
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
quote! {
|
||||
let ret = match method_id
|
||||
}.to_tokens(tokens);
|
||||
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
for method in methods{
|
||||
let ProtoMethodData{
|
||||
id,
|
||||
name,
|
||||
..
|
||||
} = method;
|
||||
|
||||
let raw_name = Ident::new(&format!("raw_{}", name), name.span());
|
||||
|
||||
|
||||
quote!{
|
||||
#id => self.#raw_name(data).await,
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
quote!{
|
||||
v =>
|
||||
}.to_tokens(tokens);
|
||||
|
||||
|
||||
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
quote!{
|
||||
log::error!("(protocol {})unimplemented method id called on protocol: {}", #id, v);
|
||||
#optional_notimpl_return
|
||||
}.to_tokens(tokens);
|
||||
if self.has_returns {
|
||||
quote! {
|
||||
Err(rnex_core::rmc::response::ErrorCode::Core_NotImplemented)
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
};
|
||||
#optional_result_sendback
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Semi::default().to_tokens(tokens);
|
||||
|
||||
if *has_returns{
|
||||
quote!{
|
||||
rnex_core::rmc::response::send_result(
|
||||
remote_response_connection,
|
||||
ret,
|
||||
#id,
|
||||
method_id,
|
||||
call_id,
|
||||
).await
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
// this gives us the name which the identifier of the corresponding Raw trait
|
||||
let raw_name = Ident::new(&format!("Raw{}", name), name.span());
|
||||
let proto_raw_methods = fold_tokenable(self.methods.iter().map(|m| generate_raw_method(m)));
|
||||
let rmc_call_proto = generate_rmc_call_proto();
|
||||
|
||||
// boilerplate tokens which all raw traits need
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_must_use)]
|
||||
pub trait #raw_name: #name{
|
||||
#proto_raw_methods
|
||||
#rmc_call_proto
|
||||
}
|
||||
impl<T: #name> #raw_name for T{}
|
||||
}
|
||||
.to_token_stream()
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
|
||||
fn generate_raw_remote_trait(&self) -> TokenStream {
|
||||
fn generate_raw_remote_trait(&self, tokens: &mut TokenStream) {
|
||||
let Self {
|
||||
has_returns,
|
||||
name,
|
||||
|
|
@ -324,92 +207,101 @@ impl RmcProtocolData {
|
|||
|
||||
// this gives us the name which the identifier of the corresponding Raw trait
|
||||
let remote_name = Ident::new(&format!("Remote{}", name), name.span());
|
||||
let generate_remote_method = |m: &ProtoMethodData| -> TokenStream {
|
||||
let ProtoMethodData {
|
||||
name,
|
||||
parameters,
|
||||
ret_val,
|
||||
attributes,
|
||||
id: method_id,
|
||||
} = m;
|
||||
|
||||
let params = fold_tokenable(parameters.iter().map(|(ident, ty, attr)| {
|
||||
let attrs = fold_tokenable(attr.iter());
|
||||
quote! { #attrs #ident: #ty, }
|
||||
}));
|
||||
|
||||
let optional_questionmark_operator = if self.has_returns {
|
||||
quote! {
|
||||
?
|
||||
}
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
|
||||
let param_serialize = fold_tokenable(parameters.iter().map(|(name, ty, attrs)|{
|
||||
let attrs = fold_tokenable(attrs.iter());
|
||||
quote!{
|
||||
#attrs
|
||||
rnex_core::result::ResultExtension::display_err_or_some(
|
||||
<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(
|
||||
&#name,
|
||||
&mut cursor
|
||||
)
|
||||
).ok_or(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument)#optional_questionmark_operator ;
|
||||
}
|
||||
}));
|
||||
|
||||
let make_call = if *has_returns {
|
||||
quote! {
|
||||
rnex_core::result::ResultExtension::display_err_or_some(
|
||||
rmc_conn.make_raw_call(&message).await
|
||||
).ok_or(rnex_core::rmc::response::ErrorCode::Core_Exception)
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
rnex_core::result::ResultExtension::display_err_or_some(
|
||||
rmc_conn.make_raw_call_no_response(&message).await
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let attribs = fold_tokenable(attributes.iter());
|
||||
|
||||
quote! {
|
||||
#attribs
|
||||
async fn #name(&self, #params) #ret_val{
|
||||
let mut send_data = ::std::vec::Vec::new();
|
||||
let mut cursor = ::std::io::Cursor::new(&mut send_data);
|
||||
#param_serialize
|
||||
|
||||
let call_id = rand::random();
|
||||
|
||||
let message = rnex_core::rmc::message::RMCMessage{
|
||||
call_id,
|
||||
method_id: #method_id,
|
||||
protocol_id: #proto_id,
|
||||
rest_of_data: send_data
|
||||
};
|
||||
|
||||
let rmc_conn = <Self as rnex_core::rmc::protocols::HasRmcConnection>::get_connection(self);
|
||||
|
||||
#make_call
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let remote_methods = fold_tokenable(methods.iter().map(|m| generate_remote_method(m)));
|
||||
|
||||
// boilerplate tokens which all raw traits need
|
||||
quote! {
|
||||
#[doc(hidden)]
|
||||
#[allow(unused_must_use)]
|
||||
pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection{
|
||||
#remote_methods
|
||||
}
|
||||
pub trait #remote_name: rnex_core::rmc::protocols::HasRmcConnection
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
|
||||
// generate the body of the raw protocol trait
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
//generate each raw method
|
||||
for method in methods{
|
||||
let ProtoMethodData {
|
||||
name,
|
||||
parameters,
|
||||
ret_val,
|
||||
id: method_id,
|
||||
..
|
||||
} = method;
|
||||
|
||||
quote!{
|
||||
async fn #name
|
||||
}.to_tokens(tokens);
|
||||
|
||||
Paren::default().surround(tokens, |tokens|{
|
||||
quote!{ &self, }.to_tokens(tokens);
|
||||
for (param_ident, param_type) in parameters{
|
||||
quote!{ #param_ident: #param_type, }.to_tokens(tokens);
|
||||
}
|
||||
});
|
||||
|
||||
quote!{
|
||||
#ret_val
|
||||
}.to_tokens(tokens);
|
||||
|
||||
Brace::default().surround(tokens, |tokens|{
|
||||
quote! {
|
||||
let mut send_data = Vec::new();
|
||||
let mut cursor = ::std::io::Cursor::new(&mut send_data);
|
||||
}.to_tokens(tokens);
|
||||
|
||||
for (param_name, param_type) in parameters{
|
||||
quote!{
|
||||
rnex_core::result::ResultExtension::display_err_or_some(
|
||||
<#param_type as rnex_core::rmc::structures::RmcSerialize>::serialize(
|
||||
&#param_name,
|
||||
&mut cursor
|
||||
)
|
||||
).ok_or(rnex_core::rmc::response::ErrorCode::Core_InvalidArgument)
|
||||
}.to_tokens(tokens);
|
||||
if self.has_returns {
|
||||
quote! {
|
||||
?;
|
||||
}.to_tokens(tokens)
|
||||
} else {
|
||||
quote! {
|
||||
;
|
||||
}.to_tokens(tokens)
|
||||
}
|
||||
}
|
||||
|
||||
quote!{
|
||||
let call_id = rand::random();
|
||||
|
||||
let message = rnex_core::rmc::message::RMCMessage{
|
||||
call_id,
|
||||
method_id: #method_id,
|
||||
protocol_id: #proto_id,
|
||||
rest_of_data: send_data
|
||||
};
|
||||
|
||||
let rmc_conn = <Self as rnex_core::rmc::protocols::HasRmcConnection>::get_connection(self);
|
||||
}.to_tokens(tokens);
|
||||
|
||||
if *has_returns{
|
||||
quote!{
|
||||
rnex_core::result::ResultExtension::display_err_or_some(
|
||||
rmc_conn.make_raw_call(&message).await
|
||||
).ok_or(rnex_core::rmc::response::ErrorCode::Core_Exception)
|
||||
}.to_tokens(tokens);
|
||||
} else {
|
||||
quote!{
|
||||
rnex_core::result::ResultExtension::display_err_or_some(
|
||||
rmc_conn.make_raw_call_no_response(&message).await
|
||||
);
|
||||
}.to_tokens(tokens);
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn generate_raw_info(&self) -> TokenStream {
|
||||
fn generate_raw_info(&self, tokens: &mut TokenStream) {
|
||||
let Self { name, id, .. } = self;
|
||||
|
||||
let raw_info_name = Ident::new(&format!("Raw{}Info", name), Span::call_site());
|
||||
|
|
@ -422,13 +314,14 @@ impl RmcProtocolData {
|
|||
pub const PROTOCOL_ID: u16 = #id;
|
||||
}
|
||||
}
|
||||
.to_tokens(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
impl ToTokens for RmcProtocolData {
|
||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||
self.generate_raw_trait().to_tokens(tokens);
|
||||
self.generate_raw_info().to_tokens(tokens);
|
||||
self.generate_raw_remote_trait().to_tokens(tokens);
|
||||
self.generate_raw_trait(tokens);
|
||||
self.generate_raw_info(tokens);
|
||||
self.generate_raw_remote_trait(tokens);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,426 +0,0 @@
|
|||
use proc_macro2::{Literal, Span, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
bracketed, parse::Parse, punctuated::Punctuated, token::Bracket, DataEnum, DataStruct,
|
||||
DeriveInput, Field, Fields, Ident, Meta, Token, Variant,
|
||||
};
|
||||
|
||||
use crate::util::fold_tokenable;
|
||||
|
||||
struct RmcStructAttrVersion {
|
||||
bracket: Bracket,
|
||||
delim: Token![,],
|
||||
feature_name: Literal,
|
||||
struct_version: Literal,
|
||||
}
|
||||
|
||||
struct RmcStructAttr {
|
||||
base_ver: Literal,
|
||||
versions: Option<(Token![,], Punctuated<RmcStructAttrVersion, Token![,]>)>,
|
||||
}
|
||||
|
||||
impl Parse for RmcStructAttr {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let base_ver = input.parse()?;
|
||||
|
||||
if let Some(seperator) = input.parse()? {
|
||||
let mut punctuated = Punctuated::new();
|
||||
loop {
|
||||
punctuated.push_value(input.parse()?);
|
||||
if let Some(punct) = input.parse()? {
|
||||
punctuated.push_punct(punct);
|
||||
} else {
|
||||
return Ok(Self {
|
||||
base_ver,
|
||||
versions: Some((seperator, punctuated)),
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Ok(Self {
|
||||
base_ver,
|
||||
versions: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcStructAttr {
|
||||
fn versions(&self) -> impl Iterator<Item = &RmcStructAttrVersion> {
|
||||
self.versions.iter().flat_map(|v| v.1.iter())
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for RmcStructAttrVersion {
|
||||
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
|
||||
let content;
|
||||
let bracket = bracketed!(content in input);
|
||||
let (feature_name, delim, struct_version) =
|
||||
content.call(|s| Ok((s.parse()?, s.parse()?, s.parse()?)))?;
|
||||
|
||||
Ok(Self {
|
||||
bracket,
|
||||
delim,
|
||||
feature_name,
|
||||
struct_version,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_write_size_struct(
|
||||
s: &DataStruct,
|
||||
with_potential_header: bool,
|
||||
) -> proc_macro2::TokenStream {
|
||||
// this is fine and works because of a quirk where the sizes of the structs dont change
|
||||
// if we ignore wether or not a struct extends the other struct or has it as a field
|
||||
|
||||
let base_size = fold_tokenable(s.fields.iter().map(|f| {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||
if let Some(i) = a.meta.path().get_ident() {
|
||||
i.to_string() != "extends"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
quote! {
|
||||
#attrs
|
||||
sum += rnex_core::rmc::structures::RmcSerialize::serialize_write_size(&self.#ident)?;
|
||||
}
|
||||
}));
|
||||
let optional_struct_header_calc = if with_potential_header {
|
||||
quote! { sum += (if rnex_core::config::FEATURE_HAS_STRUCT_HEADER{ 5 } else { 0 }); }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
quote! {
|
||||
let mut sum = 0;
|
||||
#base_size
|
||||
#optional_struct_header_calc
|
||||
Ok(sum)
|
||||
}
|
||||
}
|
||||
pub fn generate_serialize_struct(
|
||||
extended_struct: Option<&Field>,
|
||||
elems: &[&Field],
|
||||
with_header: bool,
|
||||
) -> proc_macro2::TokenStream {
|
||||
fn gen_elem_serialize(f: &Field) -> TokenStream {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||
if let Some(i) = a.meta.path().get_ident() {
|
||||
i.to_string() != "extends"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
quote! {
|
||||
#attrs
|
||||
rnex_core::rmc::structures::RmcSerialize::serialize(&self.#ident, writer)?;
|
||||
}
|
||||
}
|
||||
let optional_extended_struct = if let Some(f) = extended_struct {
|
||||
gen_elem_serialize(f)
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
let elems = fold_tokenable(elems.iter().map(|e| gen_elem_serialize(e)));
|
||||
let ser_body = if with_header {
|
||||
quote! {
|
||||
rnex_core::rmc::structures::rmc_struct::write_struct(
|
||||
writer,
|
||||
Self::version().unwrap(),
|
||||
rnex_core::rmc::structures::helpers::len_of_write(
|
||||
|writer|{
|
||||
#elems
|
||||
Ok(())
|
||||
}
|
||||
),
|
||||
|writer|{
|
||||
#elems
|
||||
Ok(())
|
||||
}
|
||||
)?;
|
||||
}
|
||||
} else {
|
||||
elems
|
||||
};
|
||||
|
||||
quote! {
|
||||
#optional_extended_struct
|
||||
#ser_body
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub fn generate_deserialize_struct(
|
||||
s: &DataStruct,
|
||||
extended_struct: Option<&Field>,
|
||||
elems: &[&Field],
|
||||
with_header: bool,
|
||||
) -> proc_macro2::TokenStream {
|
||||
fn gen_elem_serialize(f: &Field) -> TokenStream {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
let ty = &f.ty;
|
||||
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||
if let Some(i) = a.meta.path().get_ident() {
|
||||
i.to_string() != "extends"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
quote! {
|
||||
#attrs
|
||||
let #ident: #ty = rnex_core::rmc::structures::RmcSerialize::deserialize(reader)?;
|
||||
}
|
||||
}
|
||||
let optional_extended_struct = if let Some(f) = extended_struct {
|
||||
gen_elem_serialize(f)
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
let elems = fold_tokenable(elems.iter().map(|e| gen_elem_serialize(e)));
|
||||
let struct_ctor_content = fold_tokenable(s.fields.iter().map(|f| {
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
let attrs = fold_tokenable(f.attrs.iter().filter(|a| {
|
||||
if let Some(i) = a.meta.path().get_ident() {
|
||||
i.to_string() != "extends"
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}));
|
||||
quote! { #attrs #ident, }
|
||||
}));
|
||||
let de_body_inner = quote! {
|
||||
#elems
|
||||
Ok(Self{
|
||||
#struct_ctor_content
|
||||
})
|
||||
};
|
||||
let de_body = if with_header {
|
||||
quote! {
|
||||
Ok(rnex_core::rmc::structures::rmc_struct::read_struct(reader, Self::version().unwrap(), move |mut reader|{
|
||||
#de_body_inner
|
||||
})?)
|
||||
}
|
||||
} else {
|
||||
de_body_inner
|
||||
};
|
||||
|
||||
quote! {
|
||||
#optional_extended_struct
|
||||
#de_body
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_struct_version(attr: Option<&RmcStructAttr>) -> proc_macro2::TokenStream {
|
||||
if let Some(attr) = attr {
|
||||
let base_ver = &attr.base_ver;
|
||||
let if_else_chain = fold_tokenable(attr.versions().map(|v| {
|
||||
let version_val = &v.struct_version;
|
||||
let feature = &v.feature_name;
|
||||
quote! {
|
||||
if cfg!(feature = #feature){
|
||||
#version_val
|
||||
} else
|
||||
}
|
||||
}));
|
||||
|
||||
quote! {
|
||||
Some(#if_else_chain {
|
||||
#base_ver
|
||||
})
|
||||
}
|
||||
} else {
|
||||
quote! { None }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rmc_serialize_struct(
|
||||
s: &DataStruct,
|
||||
derive_input: &DeriveInput,
|
||||
) -> (
|
||||
proc_macro2::TokenStream,
|
||||
proc_macro2::TokenStream,
|
||||
Option<proc_macro2::TokenStream>,
|
||||
Option<proc_macro2::TokenStream>,
|
||||
) {
|
||||
let struct_attr = derive_input.attrs.iter().find(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "rmc_struct")
|
||||
&& matches!(a.meta, Meta::List(_))
|
||||
});
|
||||
|
||||
let struct_attr: Option<RmcStructAttr> = struct_attr.map(|a| a.parse_args().unwrap());
|
||||
let struct_attr = struct_attr.as_ref();
|
||||
|
||||
let extended_struct = s.fields.iter().find(|f| {
|
||||
f.attrs.iter().any(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||
})
|
||||
});
|
||||
let elements: Vec<_> = s
|
||||
.fields
|
||||
.iter()
|
||||
.filter(|f| {
|
||||
!f.attrs.iter().any(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "extends")
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
let elements = &elements[..];
|
||||
|
||||
let serialize = generate_serialize_struct(extended_struct, elements, struct_attr.is_some());
|
||||
let deserialize =
|
||||
generate_deserialize_struct(s, extended_struct, elements, struct_attr.is_some());
|
||||
let write_size = generate_write_size_struct(s, struct_attr.is_some());
|
||||
let version = generate_struct_version(struct_attr);
|
||||
|
||||
(serialize, deserialize, Some(write_size), Some(version))
|
||||
}
|
||||
|
||||
fn field_to_ident(field: &Field, idx: usize) -> Ident {
|
||||
if let Some(i) = &field.ident {
|
||||
i.clone()
|
||||
} else {
|
||||
Ident::new(&format!("field_{}", idx), Span::call_site())
|
||||
}
|
||||
}
|
||||
|
||||
fn variant_to_pattern_and_fields(variant: &Variant) -> (proc_macro2::TokenStream, Vec<Field>) {
|
||||
match &variant.fields {
|
||||
Fields::Named(n) => {
|
||||
let inner = n
|
||||
.named
|
||||
.iter()
|
||||
.map(|f| {
|
||||
let attrs = fold_tokenable(f.attrs.iter());
|
||||
let ident = f.ident.as_ref().unwrap();
|
||||
|
||||
quote! { #attrs #ident }
|
||||
})
|
||||
.reduce(|a, b| quote! {#a, #b});
|
||||
|
||||
(quote! {{#inner}}, n.named.iter().cloned().collect())
|
||||
}
|
||||
Fields::Unnamed(n) => {
|
||||
let inner = n
|
||||
.unnamed
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, f)| {
|
||||
let attrs = fold_tokenable(f.attrs.iter());
|
||||
let name = field_to_ident(f, i);
|
||||
|
||||
quote! { #attrs #name }
|
||||
})
|
||||
.reduce(|a, b| quote! {#a, #b});
|
||||
|
||||
(quote! {(#inner)}, n.unnamed.iter().cloned().collect())
|
||||
}
|
||||
Fields::Unit => (quote! {}, vec![]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rmc_generate_serialize_enum(
|
||||
enum_data: &DataEnum,
|
||||
repr_ty: &Ident,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let match_content = fold_tokenable(enum_data.variants.iter().map(|v|{
|
||||
let ident = &v.ident;
|
||||
let descriminant = &v.discriminant.as_ref().expect("every variant must have a descriminant to be a valid rmc struct").1;
|
||||
let (pattern, fields) = variant_to_pattern_and_fields(v);
|
||||
let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)|{
|
||||
let ty = &f.ty;
|
||||
let name = field_to_ident(&f, i);
|
||||
quote! {<#ty as rnex_core::rmc::structures::RmcSerialize>::serialize(#name, writer)?;}
|
||||
}));
|
||||
quote!{
|
||||
Self::#ident #pattern => {
|
||||
<#repr_ty as rnex_core::rmc::structures::RmcSerialize>::serialize(&#descriminant, writer)?;
|
||||
#inner
|
||||
}
|
||||
}
|
||||
}));
|
||||
quote! {
|
||||
match self{
|
||||
#match_content
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub fn rmc_generate_deserialize_enum(
|
||||
enum_data: &DataEnum,
|
||||
repr_ty: &Ident,
|
||||
) -> proc_macro2::TokenStream {
|
||||
let match_content = fold_tokenable(enum_data.variants.iter().map(|v| {
|
||||
let ident = &v.ident;
|
||||
let descriminant = &v
|
||||
.discriminant
|
||||
.as_ref()
|
||||
.expect("every variant must have a descriminant to be a valid rmc struct")
|
||||
.1;
|
||||
let (pattern, fields) = variant_to_pattern_and_fields(v);
|
||||
let inner = fold_tokenable(fields.iter().enumerate().map(|(i, f)| {
|
||||
let ty = &f.ty;
|
||||
let name = field_to_ident(&f, i);
|
||||
quote! {let #name = <#ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?;}
|
||||
}));
|
||||
quote! {
|
||||
#descriminant => {
|
||||
#inner
|
||||
|
||||
Self::#ident #pattern
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
quote! {
|
||||
let discriminant = <#repr_ty as rnex_core::rmc::structures::RmcSerialize>::deserialize(reader)?;
|
||||
|
||||
Ok(match discriminant{
|
||||
#match_content
|
||||
v => {
|
||||
return Err(rnex_core::rmc::structures::Error::UnexpectedValue(v as u64))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rmc_serialize_enum(
|
||||
enum_data: &DataEnum,
|
||||
derive_input: &DeriveInput,
|
||||
) -> (
|
||||
proc_macro2::TokenStream,
|
||||
proc_macro2::TokenStream,
|
||||
Option<proc_macro2::TokenStream>,
|
||||
Option<proc_macro2::TokenStream>,
|
||||
) {
|
||||
let repr_attr = derive_input.attrs.iter().find(|a| {
|
||||
a.path().segments.len() == 1
|
||||
&& a.path()
|
||||
.segments
|
||||
.first()
|
||||
.is_some_and(|p| p.ident.to_string() == "repr")
|
||||
});
|
||||
let Some(repr_attr) = repr_attr else {
|
||||
panic!("missing repr attribute");
|
||||
};
|
||||
|
||||
let ty: Ident = repr_attr.parse_args().unwrap();
|
||||
|
||||
let serialize = rmc_generate_serialize_enum(&enum_data, &ty);
|
||||
let deserialize = rmc_generate_deserialize_enum(&enum_data, &ty);
|
||||
|
||||
(serialize, deserialize, None, None)
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::ToTokens;
|
||||
|
||||
// todo: return a wrapper struct implementing ToTokens over the iterator instead as to avoid unnescesary allocations with the token stream
|
||||
pub fn fold_tokenable<T: ToTokens>(list: impl Iterator<Item = T>) -> TokenStream {
|
||||
list.fold(TokenStream::new(), |mut s, i| {
|
||||
i.to_tokens(&mut s);
|
||||
s
|
||||
})
|
||||
}
|
||||
|
|
@ -210,7 +210,6 @@ pub async fn new_backend_connection(
|
|||
mod test {
|
||||
use crate::{VIRTUAL_PORT_INSECURE, VIRTUAL_PORT_SECURE};
|
||||
|
||||
#[test]
|
||||
fn test_virtual_port_correct() {
|
||||
println!("{:?}", VIRTUAL_PORT_INSECURE);
|
||||
println!("{:?}", VIRTUAL_PORT_SECURE);
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ log = "0.4.25"
|
|||
cfg-if = "1.0.4"
|
||||
proxy-common = {path = "../proxy-common"}
|
||||
hmac = "0.12.1"
|
||||
md-5 = "^0.10.6"
|
||||
md-5 = "^0.11.0"
|
||||
|
||||
[features]
|
||||
prudpv0 = []
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ edition = "2024"
|
|||
bytemuck = { version = "1.23.1", features = ["derive"] }
|
||||
tokio = { version = "1.47.0", features = ["full"] }
|
||||
hmac = "0.12.1"
|
||||
md-5 = "^0.10.6"
|
||||
md-5 = "^0.11.0"
|
||||
rc4 = "0.1.0"
|
||||
v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" }
|
||||
thiserror = "2.0.12"
|
||||
|
|
|
|||
|
|
@ -447,7 +447,7 @@ mod test {
|
|||
|
||||
let bytes = &bytes[0x6..];
|
||||
|
||||
let _: [u8; 8] = bytes.try_into().unwrap();
|
||||
let header_data: [u8; 8] = bytes.try_into().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
14
renovate.json
Normal file
14
renovate.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": ["config:recommended"],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"matchUpdateTypes": ["major"],
|
||||
"automerge": false
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@ log = "0.4.25"
|
|||
rand = "0.8.5"
|
||||
cfg-if = "1.0.4"
|
||||
hmac = "0.12.1"
|
||||
md-5 = "^0.10.6"
|
||||
md-5 = "^0.11.0"
|
||||
tokio = { version = "1.43.0", features = ["full"] }
|
||||
hex = "0.4.3"
|
||||
|
||||
|
|
@ -49,10 +49,8 @@ third-notif-param = []
|
|||
v3-4-0 = ["v3-3-2", "third-notif-param", "rmc_struct_header"]
|
||||
v3-5-0 = ["v3-4-0"]
|
||||
v3-8-15 = ["v3-5-0"]
|
||||
v3-10-22 = ["v3-8-15"]
|
||||
v4-3-11 = ["v3-8-15"]
|
||||
nx = ["big_pid"]
|
||||
splatoon = []
|
||||
datastore = ["database-support", "v3-8-15", "dep:aws-sdk-s3", "dep:aws-config"]
|
||||
database-support = ["dep:sqlx"]
|
||||
|
||||
|
|
|
|||
|
|
@ -115,16 +115,9 @@ fn read_bounds_string<T: FromStr>(str: &str) -> Option<(T, T)> {
|
|||
}
|
||||
|
||||
fn check_bounds_str<T: FromStr + PartialOrd>(compare: T, str: &str) -> Option<bool> {
|
||||
if let Some(bounds) = read_bounds_string::<T>(str) {
|
||||
return Some(bounds.0 <= compare && compare <= bounds.1);
|
||||
}
|
||||
if let Ok(val) = T::from_str(str) {
|
||||
return Some(val == compare);
|
||||
}
|
||||
if str.is_empty() {
|
||||
return Some(true);
|
||||
}
|
||||
None
|
||||
let bounds: (T, T) = read_bounds_string(str)?;
|
||||
|
||||
Some(bounds.0 <= compare && compare <= bounds.1)
|
||||
}
|
||||
|
||||
pub async fn broadcast_notification<T: AsRef<User>>(
|
||||
|
|
@ -400,32 +393,32 @@ impl ExtendedMatchmakeSession {
|
|||
return Ok(false);
|
||||
}
|
||||
|
||||
#[cfg(feature = "splatoon")]
|
||||
if search_criteria
|
||||
.attribs
|
||||
.get(0)
|
||||
.map(|str| str.parse().ok())
|
||||
.flatten()
|
||||
!= self.session.attributes.get(0).map(|v| *v)
|
||||
{
|
||||
if search_criteria.attribs.get(0).is_some_and(|s| {
|
||||
self.session
|
||||
.attributes
|
||||
.get(0)
|
||||
.is_some_and(|a| s.0.contains(a))
|
||||
}) {
|
||||
return Ok(false);
|
||||
}
|
||||
if search_criteria.attribs.get(2).is_some_and(|s| {
|
||||
self.session
|
||||
.attributes
|
||||
.get(2)
|
||||
.is_some_and(|a| s.0.contains(a))
|
||||
}) {
|
||||
return Ok(false);
|
||||
}
|
||||
if search_criteria.attribs.get(3).is_some_and(|s| {
|
||||
self.session
|
||||
.attributes
|
||||
.get(3)
|
||||
.is_some_and(|a| s.0.contains(a))
|
||||
}) {
|
||||
return Ok(false);
|
||||
}
|
||||
return Ok(false);
|
||||
}
|
||||
if search_criteria
|
||||
.attribs
|
||||
.get(2)
|
||||
.map(|str| str.parse().ok())
|
||||
.flatten()
|
||||
!= self.session.attributes.get(2).map(|v| *v)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
if search_criteria
|
||||
.attribs
|
||||
.get(3)
|
||||
.map(|str| str.parse().ok())
|
||||
.flatten()
|
||||
!= self.session.attributes.get(3).map(|v| *v)
|
||||
{
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ use rnex_core::rmc::protocols::notifications::notification_types::{
|
|||
};
|
||||
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
||||
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||
use rnex_core::rmc::protocols::util::{RawUtility, RawUtilityInfo, RemoteUtility, Utility};
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
use rnex_core::rmc::structures::any::Any;
|
||||
use rnex_core::rmc::structures::matchmake::{
|
||||
|
|
@ -40,7 +39,9 @@ use cfg_if::cfg_if;
|
|||
use log::{error, info};
|
||||
use macros::rmc_struct;
|
||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||
use rnex_core::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||
use rnex_core::rmc::protocols::notifications::{
|
||||
self, Notification, NotificationEvent, RemoteNotification,
|
||||
};
|
||||
use rnex_core::rmc::protocols::ranking::{
|
||||
CompetitionRankingGetParam, CompetitionRankingScoreData, CompetitionRankingScoreInfo,
|
||||
};
|
||||
|
|
@ -51,7 +52,7 @@ use rnex_core::rmc::structures::ranking::UploadCompetitionData;
|
|||
use std::sync::{Arc, Weak};
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
|
||||
use crate::rmc::structures::matchmake::MatchmakeSessionSearchCriteria;
|
||||
use crate::rmc::structures::Error;
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "datastore")] {
|
||||
|
|
@ -64,7 +65,6 @@ cfg_if! {
|
|||
Matchmake,
|
||||
NatTraversal,
|
||||
Ranking,
|
||||
Utility,
|
||||
DataStore
|
||||
}
|
||||
);
|
||||
|
|
@ -76,7 +76,6 @@ cfg_if! {
|
|||
MatchmakeExt,
|
||||
Matchmake,
|
||||
NatTraversal,
|
||||
Utility,
|
||||
Ranking
|
||||
}
|
||||
);
|
||||
|
|
@ -182,13 +181,15 @@ impl MatchmakeExtension for User {
|
|||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
#[cfg(feature = "v3-5-0")]
|
||||
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode> {
|
||||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
#[cfg(feature = "v3-5-0")]
|
||||
{
|
||||
let session = self.matchmake_manager.get_session(gid).await?;
|
||||
|
||||
let mut session = session.lock().await;
|
||||
let mut session = session.lock().await;
|
||||
|
||||
session.session.progress_score = progress;
|
||||
session.session.progress_score = progress;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -437,7 +438,7 @@ impl MatchmakeExtension for User {
|
|||
|
||||
async fn get_friend_notification_data(
|
||||
&self,
|
||||
_ty: i32,
|
||||
ty: i32,
|
||||
) -> Result<Vec<NotificationEvent>, ErrorCode> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
|
@ -498,7 +499,7 @@ impl MatchmakeExtension for User {
|
|||
&self,
|
||||
gid: u32,
|
||||
message: String,
|
||||
_dont_care_block_list: bool,
|
||||
dont_care_block_list: bool,
|
||||
//participation_count: u16,
|
||||
) -> Result<Vec<u8>, ErrorCode> {
|
||||
let sess = self.matchmake_manager.get_session(gid).await?;
|
||||
|
|
@ -507,38 +508,6 @@ impl MatchmakeExtension for User {
|
|||
|
||||
Ok(sess.session.session_key.clone())
|
||||
}
|
||||
|
||||
async fn auto_matchmake_with_search_criteria_postpone(
|
||||
&self,
|
||||
criteria: Vec<MatchmakeSessionSearchCriteria>,
|
||||
gathering: Any,
|
||||
join_message: String,
|
||||
) -> Result<Any, ErrorCode> {
|
||||
let session: MatchmakeSession = gathering
|
||||
.try_get()
|
||||
.map(|v| v.ok())
|
||||
.flatten()
|
||||
.ok_or(ErrorCode::Core_InvalidArgument)?;
|
||||
|
||||
println!("{:?}", criteria);
|
||||
|
||||
let session = self
|
||||
.auto_matchmake_with_param_postpone(AutoMatchmakeParam {
|
||||
matchmake_session: session,
|
||||
additional_participants: vec![],
|
||||
gid_for_participation_check: 0,
|
||||
auto_matchmake_option: 0,
|
||||
join_message,
|
||||
participation_count: 0,
|
||||
search_criteria: criteria,
|
||||
target_gids: vec![],
|
||||
})
|
||||
.await?;
|
||||
|
||||
let any = Any::new(&session).map_err(|_| ErrorCode::Core_SystemError)?;
|
||||
|
||||
Ok(any)
|
||||
}
|
||||
}
|
||||
|
||||
impl Matchmake for User {
|
||||
|
|
@ -798,12 +767,6 @@ fn fetch_team_votes(fest_id: u32) -> Result<Vec<u32>, ErrorCode> {
|
|||
})
|
||||
}
|
||||
|
||||
impl Utility for User {
|
||||
async fn acquire_nex_unique_id(&self) -> Result<u64, ErrorCode> {
|
||||
return Ok(rand::random());
|
||||
}
|
||||
}
|
||||
|
||||
impl Ranking for User {
|
||||
async fn competition_ranking_get_param(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use rnex_core::rmc::structures::matchmake::{
|
|||
|
||||
use crate::rmc::protocols::notifications::NotificationEvent;
|
||||
use crate::rmc::structures::any::Any;
|
||||
use crate::rmc::structures::matchmake::MatchmakeSessionSearchCriteria;
|
||||
|
||||
#[rmc_proto(109)]
|
||||
pub trait MatchmakeExtension {
|
||||
|
|
@ -36,13 +35,6 @@ pub trait MatchmakeExtension {
|
|||
&self,
|
||||
ty: i32,
|
||||
) -> Result<Vec<NotificationEvent>, ErrorCode>;
|
||||
#[method_id(15)]
|
||||
async fn auto_matchmake_with_search_criteria_postpone(
|
||||
&self,
|
||||
criteria: Vec<MatchmakeSessionSearchCriteria>,
|
||||
gathering: Any,
|
||||
join_msg: String,
|
||||
) -> Result<Any, ErrorCode>;
|
||||
|
||||
#[method_id(30)]
|
||||
async fn join_matchmake_session_ex(
|
||||
|
|
@ -66,7 +58,6 @@ pub trait MatchmakeExtension {
|
|||
async fn get_playing_session(&self, pids: Vec<u32>) -> Result<Vec<()>, ErrorCode>;
|
||||
|
||||
#[method_id(34)]
|
||||
#[cfg(feature = "v3-5-0")]
|
||||
async fn update_progress_score(&self, gid: u32, progress: u8) -> Result<(), ErrorCode>;
|
||||
#[method_id(38)]
|
||||
async fn create_matchmake_session_with_param(
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ pub mod nintendo_notification;
|
|||
pub mod notifications;
|
||||
pub mod ranking;
|
||||
pub mod secure;
|
||||
pub mod util;
|
||||
|
||||
use crate::result::ResultExtension;
|
||||
use crate::rmc::message::RMCMessage;
|
||||
|
|
@ -21,6 +20,7 @@ use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
|
|||
use crate::rmc::structures;
|
||||
use crate::rmc::structures::RmcSerialize;
|
||||
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
|
||||
use futures::FutureExt;
|
||||
use log::{error, info};
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
use macros::{method_id, rmc_proto};
|
||||
|
||||
use rnex_core::rmc::response::ErrorCode;
|
||||
|
||||
#[rmc_proto(110)]
|
||||
pub trait Utility {
|
||||
#[method_id(1)]
|
||||
async fn acquire_nex_unique_id(&self) -> Result<u64, ErrorCode>;
|
||||
}
|
||||
|
|
@ -43,3 +43,60 @@ impl Any {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::rmc::structures::{
|
||||
RmcSerialize,
|
||||
any::Any,
|
||||
matchmake::{Gathering, MatchmakeSession},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let any = Any {
|
||||
name: "MatchmakeSession".into(),
|
||||
data: [
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 98, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0,
|
||||
0, 0, 0, 0, 0, 20, 0, 68, 111, 111, 114, 115, 32, 70, 114, 105, 101, 110, 100, 32,
|
||||
73, 110, 118, 105, 116, 101, 0, 0, 0, 0, 0, 6, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 2, 3, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
]
|
||||
.into(),
|
||||
};
|
||||
|
||||
println!("{}", hex::encode(&any.data));
|
||||
|
||||
let _: MatchmakeSession = any.try_get().unwrap().unwrap();
|
||||
let sess = MatchmakeSession {
|
||||
gathering: Gathering {
|
||||
self_gid: 0,
|
||||
owner_pid: 0,
|
||||
host_pid: 0,
|
||||
minimum_participants: 2,
|
||||
maximum_participants: 2,
|
||||
participant_policy: 98,
|
||||
policy_argument: 0,
|
||||
flags: 32,
|
||||
state: 0,
|
||||
description: "Doors Friend Invite".into(),
|
||||
},
|
||||
gamemode: 0,
|
||||
attributes: [2, 3, 0, 0, 0, 0].into(),
|
||||
open_participation: false,
|
||||
matchmake_system_type: 2,
|
||||
application_buffer: [1, 2, 3].into(),
|
||||
participation_count: 0,
|
||||
#[cfg(feature = "v3-5-0")]
|
||||
progress_score: 0,
|
||||
session_key: [].into(),
|
||||
};
|
||||
|
||||
let any = Any::new(&sess).unwrap();
|
||||
|
||||
let sess2: MatchmakeSession = any.try_get().unwrap().unwrap();
|
||||
|
||||
assert_eq!(sess, sess2)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,8 +5,6 @@ use rnex_core::rmc::structures::variant::Variant;
|
|||
|
||||
use rnex_core::PID;
|
||||
|
||||
use crate::rmc::structures::string_set::StringSet;
|
||||
|
||||
// rmc structure
|
||||
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||
#[rmc_struct(0)]
|
||||
|
|
@ -24,7 +22,7 @@ pub struct Gathering {
|
|||
}
|
||||
|
||||
// rmc structure
|
||||
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct MatchmakeParam {
|
||||
pub params: Vec<(String, Variant)>,
|
||||
|
|
@ -32,7 +30,7 @@ pub struct MatchmakeParam {
|
|||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "v3-5-0")]{
|
||||
#[derive(RmcSerialize, Debug, Clone, Default, PartialEq)]
|
||||
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||
#[rmc_struct(3)]
|
||||
pub struct MatchmakeSession {
|
||||
//inherits from
|
||||
|
|
@ -77,7 +75,7 @@ cfg_if! {
|
|||
#[derive(RmcSerialize, Debug, Clone)]
|
||||
#[rmc_struct(3)]
|
||||
pub struct MatchmakeSessionSearchCriteria {
|
||||
pub attribs: Vec<StringSet<u32>>,
|
||||
pub attribs: Vec<String>,
|
||||
pub game_mode: String,
|
||||
pub minimum_participants: String,
|
||||
pub maximum_participants: String,
|
||||
|
|
@ -123,40 +121,20 @@ pub struct MatchmakeBlockListParam {
|
|||
option_flag: u32,
|
||||
}
|
||||
|
||||
cfg_if! {
|
||||
if #[cfg(feature = "v3-10-22")] {
|
||||
#[derive(RmcSerialize, Debug, Clone)]
|
||||
#[rmc_struct(1)]
|
||||
pub struct JoinMatchmakeSessionParam {
|
||||
pub gid: u32,
|
||||
pub additional_participants: Vec<PID>,
|
||||
pub gid_for_participation_check: u32,
|
||||
pub join_matchmake_session_open: u32,
|
||||
pub join_matchmake_session_behavior: u8,
|
||||
pub user_password: String,
|
||||
pub system_password: String,
|
||||
pub join_message: String,
|
||||
pub participation_count: u16,
|
||||
pub extra_participant: u16,
|
||||
//pub block_list_param: MatchmakeBlockListParam
|
||||
}
|
||||
} else {
|
||||
#[derive(RmcSerialize, Debug, Clone)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct JoinMatchmakeSessionParam {
|
||||
pub gid: u32,
|
||||
pub additional_participants: Vec<PID>,
|
||||
pub gid_for_participation_check: u32,
|
||||
pub join_matchmake_session_open: u32,
|
||||
pub join_matchmake_session_behavior: u8,
|
||||
pub user_password: String,
|
||||
pub system_password: String,
|
||||
pub join_message: String,
|
||||
pub participation_count: u16,
|
||||
//pub extra_participant: u16,
|
||||
//pub block_list_param: MatchmakeBlockListParam
|
||||
}
|
||||
}
|
||||
#[derive(RmcSerialize, Debug, Clone)]
|
||||
#[rmc_struct(0)]
|
||||
pub struct JoinMatchmakeSessionParam {
|
||||
pub gid: u32,
|
||||
pub additional_participants: Vec<PID>,
|
||||
pub gid_for_participation_check: u32,
|
||||
pub join_matchmake_session_open: u32,
|
||||
pub join_matchmake_session_behavior: u8,
|
||||
pub user_password: String,
|
||||
pub system_password: String,
|
||||
pub join_message: String,
|
||||
pub participation_count: u16,
|
||||
//pub extra_participant: u16,
|
||||
//pub block_list_param: MatchmakeBlockListParam
|
||||
}
|
||||
|
||||
pub mod gathering_flags {
|
||||
|
|
|
|||
|
|
@ -13,15 +13,12 @@ pub enum Error {
|
|||
Utf8(#[from] FromUtf8Error),
|
||||
#[error("unexpected value: {0}")]
|
||||
UnexpectedValue(u64),
|
||||
#[cfg(feature = "rmc_struct_header")]
|
||||
#[error("version mismatch: {0}")]
|
||||
VersionMismatch(u8),
|
||||
#[error("an error occurred reading the station url")]
|
||||
StationUrlInvalid,
|
||||
#[error("error formatting text: {0}")]
|
||||
FormatError(#[from] fmt::Error),
|
||||
#[error("uncategorized rmc error occurred: {0}")]
|
||||
Other(Box<dyn std::error::Error + Send + Sync>),
|
||||
}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
|
@ -38,11 +35,10 @@ pub mod primitives;
|
|||
pub mod qbuffer;
|
||||
pub mod qresult;
|
||||
pub mod ranking;
|
||||
pub mod resultsrange;
|
||||
pub mod rmc_struct;
|
||||
pub mod string;
|
||||
pub mod string_set;
|
||||
pub mod variant;
|
||||
pub mod resultsrange;
|
||||
|
||||
pub trait RmcSerialize {
|
||||
fn serialize(&self, writer: &mut impl Write) -> Result<()>;
|
||||
|
|
@ -70,9 +66,6 @@ pub trait RmcSerialize {
|
|||
fn name() -> &'static str {
|
||||
"NoNameSpecified"
|
||||
}
|
||||
fn version() -> Option<u8> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl RmcSerialize for () {
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
use std::{collections::HashSet, hash::Hash, str::FromStr, string::ToString};
|
||||
|
||||
use rnex_core::rmc::structures::RmcSerialize;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct StringSet<T: FromStr + ToString + Eq>(pub HashSet<T>)
|
||||
where
|
||||
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static;
|
||||
|
||||
impl<T: FromStr + ToString + Eq + Hash> PartialEq for StringSet<T>
|
||||
where
|
||||
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0.iter().eq(&other.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromStr + ToString + Eq + Hash> ToString for StringSet<T>
|
||||
where
|
||||
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
fn to_string(&self) -> String {
|
||||
self.0
|
||||
.iter()
|
||||
.map(ToString::to_string)
|
||||
.reduce(|a, b| format!("{}|{}", a, b))
|
||||
.unwrap_or(String::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromStr + ToString + Eq + Hash> FromStr for StringSet<T>
|
||||
where
|
||||
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
type Err = Box<dyn std::error::Error + Send + Sync>;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Ok(Self(
|
||||
s.split("|")
|
||||
.filter(|v| !v.is_empty())
|
||||
.map(T::from_str)
|
||||
.try_fold(
|
||||
HashSet::new(),
|
||||
|mut a, b| -> Result<HashSet<T>, Self::Err> {
|
||||
a.insert(b.map_err(Box::new)?);
|
||||
Ok(a)
|
||||
},
|
||||
)?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromStr + ToString + Eq + Hash> RmcSerialize for StringSet<T>
|
||||
where
|
||||
<T as FromStr>::Err: std::error::Error + Send + Sync + 'static,
|
||||
{
|
||||
fn deserialize(reader: &mut impl std::io::prelude::Read) -> super::Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
Self::from_str(&String::deserialize(reader)?).map_err(super::Error::Other)
|
||||
}
|
||||
fn serialize(&self, writer: &mut impl std::io::prelude::Write) -> super::Result<()> {
|
||||
self.to_string().serialize(writer)
|
||||
}
|
||||
fn serialize_write_size(&self) -> super::Result<u32> {
|
||||
self.to_string().serialize_write_size()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::rmc::structures::string_set::StringSet;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
let str_val = "0|100|200|10|110|210|20|120|220|30|130|230";
|
||||
let set: StringSet<u32> = StringSet::from_str(str_val).unwrap();
|
||||
let string_2 = set.to_string();
|
||||
let reset: StringSet<u32> = StringSet::from_str(&string_2).unwrap();
|
||||
|
||||
for val in &set.0 {
|
||||
if !reset.0.contains(&val) {
|
||||
panic!("sets arent equivalent");
|
||||
}
|
||||
}
|
||||
|
||||
let _: StringSet<u32> = StringSet::from_str("").unwrap();
|
||||
|
||||
let _: StringSet<u32> = StringSet::from_str("10").unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ use rnex_core::rmc::structures;
|
|||
use rnex_core::rmc::structures::{Result, RmcSerialize};
|
||||
use std::io::{Read, Write};
|
||||
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub enum Variant {
|
||||
#[default]
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub struct ConnectionInitData {
|
|||
mod test {
|
||||
use std::{
|
||||
io::Cursor,
|
||||
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
net::{IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
|
|
|
|||
13
test-all.sh
13
test-all.sh
|
|
@ -1,13 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
EDITIONS=$(yq ea "." editions.yaml | yq 'keys[]')
|
||||
IFS=$'\n'
|
||||
while IFS=$'\n' read -r EDITION; do
|
||||
if [[ $(yq ea ".$EDITION.include-in-checkall" editions.yaml) == "true" ]]
|
||||
then
|
||||
export EDITION
|
||||
./test-edition.sh $EDITION
|
||||
fi
|
||||
done <<< "$EDITIONS"
|
||||
Loading…
Add table
Add a link
Reference in a new issue