Skip to content

Commit

Permalink
Convert Markdown objects to TypedData API
Browse files Browse the repository at this point in the history
The replacement API was introduced in Ruby 1.9.2 (2010),
and the old untyped data API was marked a deprecated in the documentation
as of Ruby 2.3.0 (2015)

Ref: https://bugs.ruby-lang.org/issues/19998
  • Loading branch information
byroot committed Nov 30, 2023
1 parent 3e3f0b5 commit 9dcf966
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 24 deletions.
20 changes: 15 additions & 5 deletions ext/redcarpet/rc_markdown.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ rb_redcarpet_md__free(void *markdown)
sd_markdown_free((struct sd_markdown *)markdown);
}

static const rb_data_type_t rb_redcarpet_md__type = {
"Redcarpet/md",
{
NULL, // Nothing to mark
rb_redcarpet_md__free,
},
0,
0,
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};

static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
{
VALUE rb_markdown, rb_rndr, hash, rndr_options;
Expand All @@ -111,7 +122,7 @@ static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
if (rb_obj_is_kind_of(rb_rndr, rb_cRenderHTML_TOC))
extensions |= MKDEXT_FENCED_CODE;

Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, rndr);
rndr = rb_redcarpet_rndr_unwrap(rb_rndr);

/* Merge the current options in the @options hash */
if (hash != Qnil) {
Expand All @@ -123,7 +134,7 @@ static VALUE rb_redcarpet_md__new(int argc, VALUE *argv, VALUE klass)
if (!markdown)
rb_raise(rb_eRuntimeError, "Failed to create new Renderer class");

rb_markdown = Data_Wrap_Struct(klass, NULL, rb_redcarpet_md__free, markdown);
rb_markdown = TypedData_Wrap_Struct(klass, &rb_redcarpet_md__type, markdown);
rb_iv_set(rb_markdown, "@renderer", rb_rndr);

return rb_markdown;
Expand All @@ -138,15 +149,14 @@ static VALUE rb_redcarpet_md_render(VALUE self, VALUE text)
Check_Type(text, T_STRING);

rb_rndr = rb_iv_get(self, "@renderer");
Data_Get_Struct(self, struct sd_markdown, markdown);
TypedData_Get_Struct(self, struct sd_markdown, &rb_redcarpet_md__type, markdown);

if (rb_respond_to(rb_rndr, rb_intern("preprocess")))
text = rb_funcall(rb_rndr, rb_intern("preprocess"), 1, text);
if (NIL_P(text))
return Qnil;

struct rb_redcarpet_rndr *renderer;
Data_Get_Struct(rb_rndr, struct rb_redcarpet_rndr, renderer);
struct rb_redcarpet_rndr *renderer = rb_redcarpet_rndr_unwrap(rb_rndr);
renderer->options.active_enc = rb_enc_get(text);

/* initialize buffers */
Expand Down
52 changes: 33 additions & 19 deletions ext/redcarpet/rc_render.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,17 +299,6 @@ cb_link_attribute(VALUE key, VALUE val, VALUE payload)
return 0;
}

static void
rndr_link_attributes(struct buf *ob, const struct buf *url, void *opaque)
{
struct redcarpet_renderopt *opt = opaque;
struct rb_redcarpet_rndr *rndr;

Data_Get_Struct(opt->self, struct rb_redcarpet_rndr, rndr);
Check_Type(opt->link_attributes, T_HASH);
rb_hash_foreach(opt->link_attributes, &cb_link_attribute, (VALUE)ob);
}

static struct sd_callbacks rb_redcarpet_callbacks = {
rndr_blockcode,
rndr_blockquote,
Expand Down Expand Up @@ -388,30 +377,55 @@ static const char *rb_redcarpet_method_names[] = {

static const size_t rb_redcarpet_method_count = sizeof(rb_redcarpet_method_names)/sizeof(char *);

static void rb_redcarpet_rbase_mark(struct rb_redcarpet_rndr *rndr)
static void rb_redcarpet_rbase_mark(void *data)
{
struct rb_redcarpet_rndr *rndr = (struct rb_redcarpet_rndr *)data;
if (rndr->options.link_attributes)
rb_gc_mark(rndr->options.link_attributes);
}

static void rndr_deallocate(void *rndr)
static const rb_data_type_t rb_redcarpet_rndr_type = {
"Redcarpet/rndr",
{
rb_redcarpet_rbase_mark,
RUBY_TYPED_DEFAULT_FREE,
},
0,
0,
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
};

struct rb_redcarpet_rndr * rb_redcarpet_rndr_unwrap(VALUE self)
{
xfree(rndr);
struct rb_redcarpet_rndr *rndr;
TypedData_Get_Struct(self, struct rb_redcarpet_rndr, &rb_redcarpet_rndr_type, rndr);
return rndr;
}

static VALUE rb_redcarpet_rbase_alloc(VALUE klass)
{
struct rb_redcarpet_rndr *rndr = ALLOC(struct rb_redcarpet_rndr);
memset(rndr, 0x0, sizeof(struct rb_redcarpet_rndr));
return Data_Wrap_Struct(klass, rb_redcarpet_rbase_mark, rndr_deallocate, rndr);
return TypedData_Wrap_Struct(klass, &rb_redcarpet_rndr_type, rndr);
}

static void
rndr_link_attributes(struct buf *ob, const struct buf *url, void *opaque)
{
struct redcarpet_renderopt *opt = opaque;
struct rb_redcarpet_rndr *rndr;

TypedData_Get_Struct(opt->self, struct rb_redcarpet_rndr, &rb_redcarpet_rndr_type, rndr);
Check_Type(opt->link_attributes, T_HASH);
rb_hash_foreach(opt->link_attributes, &cb_link_attribute, (VALUE)ob);
}

static void rb_redcarpet__overload(VALUE self, VALUE base_class)
{
struct rb_redcarpet_rndr *rndr;
VALUE options_ivar;

Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
TypedData_Get_Struct(self, struct rb_redcarpet_rndr, &rb_redcarpet_rndr_type, rndr);
rndr->options.self = self;
rndr->options.base_class = base_class;

Expand Down Expand Up @@ -448,7 +462,7 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
unsigned int render_flags = 0;
VALUE hash, link_attr = Qnil;

Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
TypedData_Get_Struct(self, struct rb_redcarpet_rndr, &rb_redcarpet_rndr_type, rndr);

if (rb_scan_args(argc, argv, "01", &hash) == 1) {
Check_Type(hash, T_HASH);
Expand Down Expand Up @@ -500,7 +514,7 @@ static VALUE rb_redcarpet_html_init(int argc, VALUE *argv, VALUE self)
rb_redcarpet__overload(self, rb_cRenderHTML);

if (!NIL_P(link_attr)) {
rndr->options.link_attributes = link_attr;
RB_OBJ_WRITE(self, &rndr->options.link_attributes, link_attr);
rndr->options.html.link_attributes = &rndr_link_attributes;
}

Expand All @@ -513,7 +527,7 @@ static VALUE rb_redcarpet_htmltoc_init(int argc, VALUE *argv, VALUE self)
unsigned int render_flags = HTML_TOC;
VALUE hash, nesting_level = Qnil;

Data_Get_Struct(self, struct rb_redcarpet_rndr, rndr);
TypedData_Get_Struct(self, struct rb_redcarpet_rndr, &rb_redcarpet_rndr_type, rndr);

if (rb_scan_args(argc, argv, "01", &hash) == 1) {
Check_Type(hash, T_HASH);
Expand Down
2 changes: 2 additions & 0 deletions ext/redcarpet/redcarpet.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,6 @@ struct rb_redcarpet_rndr {
struct redcarpet_renderopt options;
};

struct rb_redcarpet_rndr * rb_redcarpet_rndr_unwrap(VALUE);

#endif

0 comments on commit 9dcf966

Please sign in to comment.