Skip to content
This repository was archived by the owner on Nov 5, 2024. It is now read-only.

Commit 7d567e8

Browse files
committed
allow attaching arbirtary data to decoder and pass it to the decoding function.
this way decoder can be stateful
1 parent 187080b commit 7d567e8

File tree

6 files changed

+51
-35
lines changed

6 files changed

+51
-35
lines changed

api.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ namespace lib_ruby_parser
3333

3434
ParserOptions options(
3535
String::Copied("(eval)"),
36-
MaybeDecoder(Decoder(nullptr)),
36+
MaybeDecoder(Decoder(nullptr, nullptr)),
3737
MaybeTokenRewriter(TokenRewriter(nullptr)),
3838
true);
3939

decoder.cpp

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ namespace lib_ruby_parser
8989
}
9090

9191
// decoder
92-
Decoder::Decoder(DecoderFunction f_) : f(f_) {}
92+
Decoder::Decoder(DecoderFunction f_, void *state_) : f(f_), state(state_) {}
9393

9494
// maybe decoder
9595
MaybeDecoder::MaybeDecoder(Decoder decoder_) : decoder(decoder_) {}
@@ -99,7 +99,7 @@ namespace lib_ruby_parser
9999
}
100100
MaybeDecoder MaybeDecoder::None()
101101
{
102-
return MaybeDecoder(Decoder(nullptr));
102+
return MaybeDecoder(Decoder(nullptr, nullptr));
103103
}
104104

105105
bool MaybeDecoder::is_some() const
@@ -183,60 +183,57 @@ namespace lib_ruby_parser
183183

184184
extern "C"
185185
{
186-
DecoderBlob lib_ruby_parser__test__always_ok_decoder(void);
187-
DecoderBlob lib_ruby_parser__test__always_err_decoder(void);
186+
DecoderBlob lib_ruby_parser__test__always_ok_decoder(const char *output);
187+
DecoderBlob lib_ruby_parser__test__always_err_decoder(const char *output);
188188
}
189-
static DecoderResult call_decoder(Decoder decoder, String encoding, ByteList input)
189+
static DecoderResult call_decoder(Decoder decoder, String encoding, ByteList input, void *state)
190190
{
191191
StringBlob encoding_blob = into_blob<String, StringBlob>(std::move(encoding));
192192
ByteListBlob input_blob = into_blob<ByteList, ByteListBlob>(std::move(input));
193193
// cast fn from
194194
// (String, ByteList) -> DecoderResult
195195
// to
196196
// (StringBlob, ByteListBlob) -> DecoderResultBlob
197-
typedef DecoderResultBlob (*DecoderFunctionBlob)(StringBlob, ByteListBlob);
197+
typedef DecoderResultBlob (*DecoderFunctionBlob)(StringBlob, ByteListBlob, void *);
198198
DecoderFunctionBlob fn_blob =
199199
reinterpret_cast<DecoderFunctionBlob>(
200200
reinterpret_cast<void *>(
201201
decoder.f));
202-
DecoderResultBlob result_blob = fn_blob(encoding_blob, input_blob);
202+
DecoderResultBlob result_blob = fn_blob(encoding_blob, input_blob, state);
203203
return from_blob<DecoderResultBlob, DecoderResult>(result_blob);
204204
}
205205

206206
static void test_decoder_fields(void)
207207
{
208208
annotate_test;
209209

210-
const char *ALWAYS_OK = "always_ok";
211-
const char *ALWAYS_ERR = "always_err";
212-
213210
Decoder ok_decoder = from_blob<DecoderBlob, Decoder>(
214-
lib_ruby_parser__test__always_ok_decoder());
215-
DecoderResult ok_decoder_result = call_decoder(ok_decoder, String::Copied("utf-8"), ByteList::Copied("2 + 2", 5));
211+
lib_ruby_parser__test__always_ok_decoder("anything"));
212+
DecoderResult ok_decoder_result = call_decoder(ok_decoder, String::Copied("utf-8"), ByteList::Copied("2 + 2", 5), const_cast<char *>("foo"));
216213
assert_eq(ok_decoder_result.tag, DecoderResult::Tag::OK);
217-
assert_byte_list(ok_decoder_result.as.ok, ALWAYS_OK);
214+
assert_byte_list(ok_decoder_result.as.ok, "foo");
218215

219216
Decoder err_decoder = from_blob<DecoderBlob, Decoder>(
220-
lib_ruby_parser__test__always_err_decoder());
221-
DecoderResult err_decoder_result = call_decoder(err_decoder, String::Copied("utf-8"), ByteList::Copied("2 + 2", 5));
217+
lib_ruby_parser__test__always_err_decoder("anything"));
218+
DecoderResult err_decoder_result = call_decoder(err_decoder, String::Copied("utf-8"), ByteList::Copied("2 + 2", 5), const_cast<char *>("bar"));
222219
assert_eq(err_decoder_result.as.err.tag, InputError::Tag::DECODING_ERROR);
223-
assert_string_eq(err_decoder_result.as.err.as.unsupported_encoding, ALWAYS_ERR);
220+
assert_string_eq(err_decoder_result.as.err.as.unsupported_encoding, "bar");
224221
}
225222

226223
extern "C"
227224
{
228-
MaybeDecoderBlob lib_ruby_parser__test__some_always_ok_decoder(void);
225+
MaybeDecoderBlob lib_ruby_parser__test__some_always_ok_decoder(const char *output);
229226
MaybeDecoderBlob lib_ruby_parser__test__none_decoder(void);
230227
}
231228
static void test_maybe_decoder_fields(void)
232229
{
233230
annotate_test;
234231

235232
Decoder always_ok_decoder = from_blob<DecoderBlob, Decoder>(
236-
lib_ruby_parser__test__always_ok_decoder());
233+
lib_ruby_parser__test__always_ok_decoder("foo"));
237234

238235
MaybeDecoder some_decoder = from_blob<MaybeDecoderBlob, MaybeDecoder>(
239-
lib_ruby_parser__test__some_always_ok_decoder());
236+
lib_ruby_parser__test__some_always_ok_decoder("foo"));
240237
assert(some_decoder.is_some());
241238

242239
assert_eq(some_decoder.decoder.f, always_ok_decoder.f);

decoder.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,14 @@ namespace lib_ruby_parser
7171
static DecoderResult Err(InputError err);
7272
};
7373

74-
typedef DecoderResult (*DecoderFunction)(String, ByteList);
74+
typedef DecoderResult (*DecoderFunction)(String, ByteList, void *);
7575
class Decoder
7676
{
7777
public:
7878
DecoderFunction f;
79+
void *state;
7980

80-
explicit Decoder(DecoderFunction f);
81+
explicit Decoder(DecoderFunction f, void *state);
8182
};
8283

8384
class MaybeDecoder

ruby-parser-cpp/src/decoder.rs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,53 +52,70 @@ pub extern "C" fn LIB_RUBY_PARSER_drop_decoder_result(decoder_result: *mut Decod
5252
#[repr(C)]
5353
#[derive(Debug)]
5454
pub struct Decoder {
55-
pub f: extern "C" fn(encoding: StringBlob, input: ByteListBlob) -> DecoderResultBlob,
55+
pub f: extern "C" fn(
56+
encoding: StringBlob,
57+
input: ByteListBlob,
58+
state: *const std::ffi::c_void,
59+
) -> DecoderResultBlob,
60+
pub state: *const std::ffi::c_void,
5661
}
5762

5863
#[cfg(feature = "tests")]
5964
#[no_mangle]
60-
pub extern "C" fn lib_ruby_parser__test__always_ok_decoder() -> Decoder {
65+
pub extern "C" fn lib_ruby_parser__test__always_ok_decoder(output: *const u8) -> Decoder {
6166
#[no_mangle]
6267
pub extern "C" fn lib_ruby_parser__test__always_ok_decoder_fn(
6368
encoding: StringBlob,
6469
input: ByteListBlob,
70+
state: *const std::ffi::c_void,
6571
) -> DecoderResultBlob {
6672
// do cleanup
6773
drop(String::from(encoding));
6874
drop(Vec::<u8>::from(input));
69-
// and return constant output
70-
DecoderResultBlob::from(DecoderResult::Ok("always_ok".as_bytes().to_vec()))
75+
// and return given output
76+
let output = unsafe { std::ffi::CStr::from_ptr(state as *const i8) }
77+
.to_str()
78+
.unwrap();
79+
DecoderResultBlob::from(DecoderResult::Ok(output.as_bytes().to_vec()))
7180
}
7281
Decoder {
7382
f: lib_ruby_parser__test__always_ok_decoder_fn,
83+
state: output as *const std::ffi::c_void,
7484
}
7585
}
7686

7787
#[cfg(feature = "tests")]
7888
#[no_mangle]
79-
pub extern "C" fn lib_ruby_parser__test__always_err_decoder() -> Decoder {
89+
pub extern "C" fn lib_ruby_parser__test__always_err_decoder(output: *const u8) -> Decoder {
8090
#[no_mangle]
8191
pub extern "C" fn lib_ruby_parser__test__always_err_decoder_fn(
8292
encoding: StringBlob,
8393
input: ByteListBlob,
94+
state: *const std::ffi::c_void,
8495
) -> DecoderResultBlob {
8596
// do cleanup
8697
drop(String::from(encoding));
8798
drop(Vec::<u8>::from(input));
88-
// and return constant output
89-
DecoderResultBlob::from(DecoderResult::Err(InputError::DecodingError(String::from(
90-
"always_err",
91-
))))
99+
// and return given output
100+
let output = unsafe { std::ffi::CStr::from_ptr(state as *const i8) }
101+
.to_str()
102+
.unwrap();
103+
DecoderResultBlob::from(DecoderResult::Err(InputError::DecodingError(
104+
output.to_string(),
105+
)))
92106
}
93107
Decoder {
94108
f: lib_ruby_parser__test__always_err_decoder_fn,
109+
state: output as *const std::ffi::c_void,
95110
}
96111
}
97112

98113
#[cfg(feature = "tests")]
99114
#[no_mangle]
100-
pub extern "C" fn lib_ruby_parser__test__some_always_ok_decoder() -> MaybeDecoderBlob {
101-
MaybeDecoderBlob::from(Some(lib_ruby_parser__test__always_ok_decoder()))
115+
pub extern "C" fn lib_ruby_parser__test__some_always_ok_decoder(
116+
output: *mut u8,
117+
) -> MaybeDecoderBlob {
118+
MaybeDecoderBlob::from(Some(lib_ruby_parser__test__always_ok_decoder(output)))
102119
}
103120

104121
#[cfg(feature = "tests")]

ruby-parser-cpp/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ macro_rules! blob_type {
66
#[repr(C)]
77
#[derive(Debug)]
88
pub struct $c_type {
9-
content: [u8; std::mem::size_of::<$rust_type>()],
9+
pub(crate) content: [u8; std::mem::size_of::<$rust_type>()],
1010
}
1111

1212
impl From<$rust_type> for $c_type {

ruby-parser-cpp/src/parser_options.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ impl From<CParserOptions> for lib_ruby_parser::ParserOptions {
2121
} = options;
2222

2323
let decoder = decoder.map(|decoder| {
24+
let Decoder { f, state } = decoder;
2425
lib_ruby_parser::source::Decoder::new(Box::new(move |encoding, input| {
25-
(decoder.f)(encoding.into(), input.into()).into()
26+
f(encoding.into(), input.into(), state).into()
2627
}))
2728
});
2829

0 commit comments

Comments
 (0)