Last active
November 20, 2023 07:16
-
-
Save andreivasiliu/d8cd7ebb06f54d07ec5d271ded21f8cd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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