Skip to content

Commit

Permalink
feat(proc_macro): Minimal and complete conversion to kproc-macros
Browse files Browse the repository at this point in the history
This commit deserves a bit more attention in terms of its description.

I've never been a fan of `syn` because it's a large dependency and
too complex for my use case. Additionally, I cannot remove `proc_macro2`
if I want to. For this reason, I chose to write
`kproc-macros` (https://github.com/vincenzopalazzo/kproc-macros), which
implements a very lightweight parser for Rust procedural macros and
provides an API to extend the procedural macros API to
build your own parser.

This commit introduces a basic version of the `kproc-macros`
crate that allows me to perform debugging on it.

Signed-off-by: Vincenzo Palazzo <[email protected]>
  • Loading branch information
vincenzopalazzo committed Apr 30, 2023
1 parent 8823c61 commit c0629bc
Show file tree
Hide file tree
Showing 6 changed files with 419 additions and 358 deletions.
6 changes: 2 additions & 4 deletions plugin_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,11 @@ readme = "README.md"
proc-macro = true

[dependencies]
syn = "1.0"
quote = "1.0"
darling = "0.14.1"
convert_case = "0.5.0"
serde_json = "1.0"
clightningrpc-plugin = { path = "../plugin"}
#clightningrpc-plugin = "0.3.0-beta.3"
kproc-parser = { version = "0.0.1-beta.3" }
#clightningrpc-plugin = "0.3.0-beta.7"

[dev-dependencies]
rstest = "0.10.0"
Expand Down
59 changes: 35 additions & 24 deletions plugin_macros/examples/macros_ex.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,58 @@
//! plugin macros usage example.
extern crate clightningrpc_plugin_macros;
use clightningrpc_plugin_macros::{
add_plugin_rpc, notification, plugin_register_notification, rpc_method,
};
use serde_json::{json, Value};
use clightningrpc_plugin_macros::*;

use serde_json::json;
use serde_json::Value;

use clightningrpc_plugin::commands::RPCCommand;
use clightningrpc_plugin::errors::PluginError;
use clightningrpc_plugin::plugin::Plugin;
use clightningrpc_plugin::types::LogLevel;
use clightningrpc_plugin::{add_rpc, register_notification};

#[derive(Clone)]
struct State;

#[rpc_method(
rpc_name = "foo_macro",
description = "This is a simple and short description"
)]
pub fn foo_rpc(_plugin: Plugin<()>, _request: Value) -> Result<Value, PluginError> {
/// The name of the parameters can be used only if used, otherwise can be omitted
/// the only rules that the macros require is to have a propriety with the following rules:
/// - Plugin as _plugin
/// - CLN JSON request as _request
/// The function parameter can be specified in any order.
let response = json!({"is_dynamic": _plugin.dynamic, "rpc_request": _request});
pub fn foo_rpc(plugin: &mut Plugin<State>, request: Value) -> Result<Value, PluginError> {
let response = json!({"is_dynamic": plugin.dynamic, "rpc_request": request});
Ok(response)
}

#[notification(on = "rpc_command")]
fn on_rpc(_plugin: Plugin<()>, _request: Value) {
_plugin.log(LogLevel::Info, "received an RPC notification");
fn on_rpc(plugin: &mut Plugin<State>, request: &Value) {
use clightningrpc_plugin::types::LogLevel;
plugin.log(LogLevel::Info, "received an RPC notification");
}

fn main() {
// as fist step you need to make a new plugin instance
// more docs about Plugin struct is provided under the clightning_plugin crate
let mut plugin = Plugin::new((), true);

// The macros helper that help to register a RPC method with the name
// without worry about all the rules of the library
add_plugin_rpc!(plugin, "foo_macro");

// the macros helper that help to register a notification with the
// event name without worry about the rules of the library :)
plugin_register_notification!(plugin, "rpc_command");
let mut plugin = Plugin::new(State, true);

// FIXME: this is just for now, we will write a plugin macros
// that define the definition like in the linux kernel a module is
// defined.
//
// ```
// module! {
// type: RustMinimal,
// name: "rust_minimal",
// author: "Rust for Linux Contributors",
// description: "Rust minimal sample",
// license: "GPL",
// }
// ```
let call = on_rpc();
plugin.register_notification(&call.on_event.clone(), call);
let call = foo_rpc();
plugin.add_rpc_method(
&call.name.clone(),
&call.usage.clone(),
&call.description.clone(),
call,
);
plugin.start();
}
45 changes: 45 additions & 0 deletions plugin_macros/src/attr_parser.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! A custom parser for the attributes
use std::collections::HashMap;

use kproc_parser::{
check,
kparser::{KParserError, KParserTracer},
kproc_macros::KTokenStream,
trace,
};

pub(crate) struct AttributeParser {}

impl AttributeParser {
pub fn parse(
stream: &mut KTokenStream,
tracer: &dyn KParserTracer,
) -> Result<HashMap<String, String>, KParserError> {
parse_key_values(stream, tracer)
}
}

fn parse_key_values(
stream: &mut KTokenStream,
tracer: &dyn KParserTracer,
) -> Result<HashMap<String, String>, KParserError> {
let mut hash_map = HashMap::new();
trace!(tracer, "start parsing key values");
trace!(tracer, "start with tok {}", stream.peek());
while !stream.is_end() {
let key = stream.advance();
check!("=", stream.peek())?;
let _ = stream.advance();
let value = stream.advance();
if !stream.is_end() && stream.match_tok(",") {
trace!(tracer, "removing the `,` tok");
check!(",", stream.advance())?;
}
let value = value.to_string().replace("\"", "");
trace!(tracer, "key {key} = value {value}");
hash_map.insert(key.to_string(), value.to_string());
trace!(tracer, "map is {:?}", hash_map);
}
Ok(hash_map)
}
Loading

0 comments on commit c0629bc

Please sign in to comment.