Skip to content

Instantly share code, notes, and snippets.

@andreivasiliu
Last active November 20, 2023 07:16
Show Gist options
  • Save andreivasiliu/d8cd7ebb06f54d07ec5d271ded21f8cd to your computer and use it in GitHub Desktop.
Save andreivasiliu/d8cd7ebb06f54d07ec5d271ded21f8cd to your computer and use it in GitHub Desktop.
use core::fmt::Debug;
use std::str::FromStr;
trait ArgsFromSource {
const ARG_COUNT: usize;
fn from_source(source: &Source) -> Self;
}
trait ArgFromSource {
fn from_source(source: &Source, index: usize) -> Self;
}
impl<T: FromStr> ArgFromSource for T {
fn from_source(source: &Source, index: usize) -> T {
source.get_arg(index)
}
}
impl<T1: ArgFromSource> ArgsFromSource for (T1,) {
const ARG_COUNT: usize = 1;
fn from_source(source: &Source) -> Self {
(T1::from_source(source, 0),)
}
}
impl<T1: ArgFromSource, T2: ArgFromSource> ArgsFromSource for (T1, T2) {
const ARG_COUNT: usize = 2;
fn from_source(source: &Source) -> Self {
(T1::from_source(source, 0), T2::from_source(source, 1))
}
}
trait ConfigFromSource {
fn from_source(source: &Source) -> Self;
}
impl ConfigFromSource for () {
fn from_source(_source: &Source) -> Self {
()
}
}
trait CommandSetter {
type ModuleConfig: ConfigFromSource + Debug;
type Arguments: ArgsFromSource;
fn set_from_source(config: &mut Self::ModuleConfig, arguments: Self::Arguments);
}
#[derive(Debug)]
struct Config {
setting1: i32,
setting2: i16,
}
// Technically not necessary; this will be a pointer cast
impl ConfigFromSource for Config {
fn from_source(_source: &Source) -> Self {
Config {
setting1: 0,
setting2: 0,
}
}
}
struct CommandA;
struct CommandB;
struct CommandC;
impl CommandSetter for CommandA {
type ModuleConfig = Config;
type Arguments = (i32, i16);
fn set_from_source(config: &mut Config, arguments: (i32, i16)) {
config.setting1 = arguments.0;
config.setting2 = arguments.1;
}
}
impl CommandSetter for CommandB {
type ModuleConfig = Config;
type Arguments = (i16, i32);
fn set_from_source(config: &mut Config, arguments: (i16, i32)) {
config.setting1 = arguments.1;
config.setting2 = arguments.0;
}
}
impl CommandSetter for CommandC {
type ModuleConfig = Config;
type Arguments = (i32,);
fn set_from_source(config: &mut Config, arguments: (i32,)) {
config.setting1 = arguments.0;
}
}
struct Source {
args: Vec<String>,
}
impl Source {
fn get_arg<T: FromStr>(&self, index: usize) -> T {
match T::from_str(&self.args[index]) {
Ok(v) => v,
Err(_) => panic!("Oh no"),
}
}
}
extern "C" fn f<T: CommandSetter>(source: &Source) {
let mut config = T::ModuleConfig::from_source(source);
let args = T::Arguments::from_source(source);
eprintln!("Parsing {} arguments...", T::Arguments::ARG_COUNT);
T::set_from_source(&mut config, args);
dbg!(config);
// println!("Hello: {}", T::X);
}
const FX1: extern "C" fn(source: &Source) = f::<CommandA>;
const FX2: extern "C" fn(source: &Source) = f::<CommandB>;
const FX3: extern "C" fn(source: &Source) = f::<CommandC>;
trait SetterFunctionTrait<C: ConfigFromSource, A>: Copy {
fn set_config(config: &mut C, args: A);
}
// impl<M, A1> SetterFunctionTrait<()> for fn(M, A1) where Self: Copy {
// type ModuleConfig = M;
// type Arg1 = A1;
// }
impl<C, A1, T> SetterFunctionTrait<C, (A1,)> for T
where
T: Fn(&mut C, A1) + Copy,
C: ConfigFromSource,
{
fn set_config(config: &mut C, args: (A1,)) {
}
}
extern "C" fn f2<C: ConfigFromSource, A, T: SetterFunctionTrait<C, A>>(source: &Source) {
let mut config = C::from_source(source);
}
const fn make_config_struct<C: ConfigFromSource, A, T: SetterFunctionTrait<C, A>>(f: T) -> extern "C" fn(source: &Source) {
f2::<C, A, T>
}
struct CfgStruct<C: ConfigFromSource, A, T: SetterFunctionTrait<C, A>> {
f: extern "C" fn(source: &Source),
f2: T,
p1: std::marker::PhantomData<C>,
p2: std::marker::PhantomData<A>,
}
const fn make_config_struct2<C: ConfigFromSource, A, T: SetterFunctionTrait<C, A>>(f: T) -> CfgStruct<C, A, T> {
CfgStruct {
f: f2::<C, A, T>,
f2: f,
p1: std::marker::PhantomData,
p2: std::marker::PhantomData,
}
}
fn custom_setter(a: &mut Config, b: i32) {
}
const FX4: extern "C" fn(source: &Source) = make_config_struct(custom_setter);
const FX5: extern "C" fn(source: &Source) = make_config_struct(|a: &mut Config, b: i32| {a.setting1 = b;});
fn main() {
let source = Source {
args: vec!["1".to_string(), "2".to_string()],
};
FX1(&source);
FX2(&source);
FX3(&source);
FX4(&source);
FX5(&source);
}
use std::ffi::c_void;
use ngx::{
ffi::{ngx_command_t, ngx_str_t, NGX_CONF_TAKE1, NGX_HTTP_LOC_CONF, NGX_HTTP_SRV_CONF},
http::HTTPModule,
ngx_null_command,
};
pub struct NgxCommand<M> {
ngx_command: ngx_command_t,
module_conf: std::marker::PhantomData<M>,
}
const fn compile_error_if_not_null_terminated(string: &'static str) {
if string.len() == 0 || string.as_bytes()[string.len() - 1] != 0 {
panic!("String does not end with a '\0' character.");
}
}
impl<M: HTTPModule> NgxCommand<M> {
pub const fn loc_conf<F>(name: &'static str, setter: F) -> Self
where
F: Fn(&mut M::LocConf) + Copy + 'static,
{
compile_error_if_not_null_terminated(name);
let setter: &'static F = &setter;
NgxCommand {
ngx_command: ngx_command_t {
name: ngx::ffi::ngx_str_t {
data: name.as_ptr() as *mut u8,
len: name.len(),
},
type_: (NGX_HTTP_LOC_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_TAKE1)
as ngx::ffi::ngx_uint_t,
set: Some(ngx_http_commands_set::<M::LocConf, F>),
conf: ngx::ffi::NGX_RS_HTTP_LOC_CONF_OFFSET,
offset: 0,
post: setter as *const F as *mut F as *mut c_void,
},
module_conf: std::marker::PhantomData,
}
}
fn null() -> Self {
NgxCommand {
ngx_command: ngx_null_command!(),
module_conf: std::marker::PhantomData,
}
}
}
#[repr(C)]
struct NgxCommandPost {}
const NGX_CONF_OK: *mut std::ffi::c_char = std::ptr::null_mut();
extern "C" fn ngx_http_commands_set<C, F>(
cf: *mut ngx::ffi::ngx_conf_t,
cmd: *mut ngx_command_t,
conf: *mut std::ffi::c_void,
) -> *mut std::ffi::c_char
where
F: Fn(&mut C),
{
unsafe {
let conf = &mut *(conf as *mut C);
let args = (*(*cf).args).elts as *mut ngx_str_t;
let val = (*args.add(1)).to_str();
let setter = (*cmd).post as *mut F;
(*setter)(conf);
};
NGX_CONF_OK
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment