Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 22 additions & 13 deletions rust/ruby-rbs/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ fn write_node_field_accessor(
if field.optional {
writeln!(
file,
" pub fn {}(&self) -> Option<{rust_type}> {{",
" pub fn {}(&self) -> Option<{rust_type}<'a>> {{",
field.name,
)?;
writeln!(
Expand All @@ -132,14 +132,18 @@ fn write_node_field_accessor(
writeln!(file, " }} else {{")?;
writeln!(
file,
" Some({rust_type} {{ parser: self.parser, pointer: ptr }})"
" Some({rust_type} {{ parser: self.parser, pointer: ptr, marker: PhantomData }})"
)?;
writeln!(file, " }}")?;
} else {
writeln!(file, " pub fn {}(&self) -> {rust_type} {{", field.name)?;
writeln!(
file,
" {rust_type} {{ parser: self.parser, pointer: unsafe {{ (*self.pointer).{} }} }}",
" pub fn {}(&self) -> {rust_type}<'a> {{",
field.name
)?;
writeln!(
file,
" {rust_type} {{ parser: self.parser, pointer: unsafe {{ (*self.pointer).{} }}, marker: PhantomData }}",
field.c_name()
)?;
}
Expand Down Expand Up @@ -334,19 +338,24 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {
for node in &config.nodes {
writeln!(file, "#[allow(dead_code)]")?; // TODO: Remove this once all nodes that need parser are implemented
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub struct {} {{", node.rust_name)?;
writeln!(file, "pub struct {}<'a> {{", node.rust_name)?;
writeln!(file, " parser: *mut rbs_parser_t,")?;
writeln!(
file,
" pointer: *mut {},",
convert_name(&node.name, CIdentifier::Type)
)?;
writeln!(
file,
" marker: PhantomData<&'a mut {}>",
convert_name(&node.name, CIdentifier::Type)
)?;
writeln!(file, "}}\n")?;

writeln!(file, "impl {} {{", node.rust_name)?;
writeln!(file, "impl<'a> {}<'a> {{", node.rust_name)?;
writeln!(file, " /// Converts this node to a generic node.")?;
writeln!(file, " #[must_use]")?;
writeln!(file, " pub fn as_node(self) -> Node {{")?;
writeln!(file, " pub fn as_node(self) -> Node<'a> {{")?;
writeln!(file, " Node::{}(self)", node.variant_name())?;
writeln!(file, " }}")?;
writeln!(file)?;
Expand Down Expand Up @@ -461,7 +470,7 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {
field.name.as_str()
};
if field.optional {
writeln!(file, " pub fn {name}(&self) -> Option<Node> {{")?;
writeln!(file, " pub fn {name}(&self) -> Option<Node<'a>> {{")?;
writeln!(
file,
" let ptr = unsafe {{ (*self.pointer).{} }};",
Expand All @@ -472,7 +481,7 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {
" if ptr.is_null() {{ None }} else {{ Some(Node::new(self.parser, ptr)) }}"
)?;
} else {
writeln!(file, " pub fn {name}(&self) -> Node {{")?;
writeln!(file, " pub fn {name}(&self) -> Node<'a> {{")?;
writeln!(
file,
" unsafe {{ Node::new(self.parser, (*self.pointer).{}) }}",
Expand Down Expand Up @@ -501,18 +510,18 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {

// Generate the Node enum to wrap all of the structs
writeln!(file, "#[derive(Debug)]")?;
writeln!(file, "pub enum Node {{")?;
writeln!(file, "pub enum Node<'a> {{")?;
for node in &config.nodes {
let variant_name = node
.rust_name
.strip_suffix("Node")
.unwrap_or(&node.rust_name);

writeln!(file, " {variant_name}({}),", node.rust_name)?;
writeln!(file, " {variant_name}({}<'a>),", node.rust_name)?;
}
writeln!(file, "}}")?;

writeln!(file, "impl Node {{")?;
writeln!(file, "impl Node<'_> {{")?;
writeln!(file, " #[allow(clippy::missing_safety_doc)]")?;
writeln!(
file,
Expand All @@ -525,7 +534,7 @@ fn generate(config: &Config) -> Result<(), Box<dyn Error>> {

writeln!(
file,
" rbs_node_type::{enum_name} => Self::{}({} {{ parser, pointer: node.cast::<{c_type}>() }}),",
" rbs_node_type::{enum_name} => Self::{}({} {{ parser, pointer: node.cast::<{c_type}>(), marker: PhantomData }}),",
node.variant_name(),
node.rust_name,
)?;
Expand Down
52 changes: 34 additions & 18 deletions rust/ruby-rbs/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
use rbs_encoding_type_t::RBS_ENCODING_UTF_8;
use ruby_rbs_sys::bindings::*;
use std::marker::PhantomData;
use std::sync::Once;

static INIT: Once = Once::new();
Expand All @@ -13,7 +14,7 @@ static INIT: Once = Once::new();
/// let signature = parse(rbs_code.as_bytes());
/// assert!(signature.is_ok(), "Failed to parse RBS signature");
/// ```
pub fn parse(rbs_code: &[u8]) -> Result<SignatureNode, String> {
pub fn parse(rbs_code: &[u8]) -> Result<SignatureNode<'_>, String> {
unsafe {
INIT.call_once(|| {
rbs_constant_pool_init(RBS_GLOBAL_CONSTANT_POOL, 26);
Expand All @@ -33,6 +34,7 @@ pub fn parse(rbs_code: &[u8]) -> Result<SignatureNode, String> {
let signature_node = SignatureNode {
parser,
pointer: signature,
marker: PhantomData,
};

if result {
Expand All @@ -43,15 +45,15 @@ pub fn parse(rbs_code: &[u8]) -> Result<SignatureNode, String> {
}
}

impl Drop for SignatureNode {
impl Drop for SignatureNode<'_> {
fn drop(&mut self) {
unsafe {
rbs_parser_free(self.parser);
}
}
}

impl KeywordNode {
impl KeywordNode<'_> {
pub fn name(&self) -> &[u8] {
unsafe {
let constant_ptr = rbs_constant_pool_id_to_constant(
Expand All @@ -68,33 +70,40 @@ impl KeywordNode {
}
}

pub struct NodeList {
pub struct NodeList<'a> {
parser: *mut rbs_parser_t,
pointer: *mut rbs_node_list_t,
marker: PhantomData<&'a mut rbs_node_list_t>,
}

impl NodeList {
impl<'a> NodeList<'a> {
pub fn new(parser: *mut rbs_parser_t, pointer: *mut rbs_node_list_t) -> Self {
Self { parser, pointer }
Self {
parser,
pointer,
marker: PhantomData,
}
}

/// Returns an iterator over the nodes.
#[must_use]
pub fn iter(&self) -> NodeListIter {
pub fn iter(&self) -> NodeListIter<'a> {
NodeListIter {
parser: self.parser,
current: unsafe { (*self.pointer).head },
marker: PhantomData,
}
}
}

pub struct NodeListIter {
pub struct NodeListIter<'a> {
parser: *mut rbs_parser_t,
current: *mut rbs_node_list_node_t,
marker: PhantomData<&'a mut rbs_node_list_node_t>,
}

impl Iterator for NodeListIter {
type Item = Node;
impl<'a> Iterator for NodeListIter<'a> {
type Item = Node<'a>;

fn next(&mut self) -> Option<Self::Item> {
if self.current.is_null() {
Expand All @@ -108,33 +117,40 @@ impl Iterator for NodeListIter {
}
}

pub struct RBSHash {
pub struct RBSHash<'a> {
parser: *mut rbs_parser_t,
pointer: *mut rbs_hash,
marker: PhantomData<&'a mut rbs_hash>,
}

impl RBSHash {
impl<'a> RBSHash<'a> {
pub fn new(parser: *mut rbs_parser_t, pointer: *mut rbs_hash) -> Self {
Self { parser, pointer }
Self {
parser,
pointer,
marker: PhantomData,
}
}

/// Returns an iterator over the key-value pairs.
#[must_use]
pub fn iter(&self) -> RBSHashIter {
pub fn iter(&self) -> RBSHashIter<'a> {
RBSHashIter {
parser: self.parser,
current: unsafe { (*self.pointer).head },
marker: PhantomData,
}
}
}

pub struct RBSHashIter {
pub struct RBSHashIter<'a> {
parser: *mut rbs_parser_t,
current: *mut rbs_hash_node_t,
marker: PhantomData<&'a mut rbs_hash_node_t>,
}

impl Iterator for RBSHashIter {
type Item = (Node, Node);
impl<'a> Iterator for RBSHashIter<'a> {
type Item = (Node<'a>, Node<'a>);

fn next(&mut self) -> Option<Self::Item> {
if self.current.is_null() {
Expand Down Expand Up @@ -222,7 +238,7 @@ impl RBSString {
}
}

impl SymbolNode {
impl SymbolNode<'_> {
pub fn name(&self) -> &[u8] {
unsafe {
let constant_ptr = rbs_constant_pool_id_to_constant(
Expand Down
Loading