1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
//! Ruby classes, modules and exceptions from ordinary Rust: the
//! `#[rubyclass]`, `#[rubymethods]`, `#[rubymodule]`, `#[rubyfunction]` and
//! `#[rubyerror]` attributes, and `#[derive(Mark)]` (the `derive` feature).
//!
//! ```
//! use rutie::{rubyclass, rubymethods, Class, Object, RString, VM};
//!
//! #[rubyclass(path = "Stats::Counter")]
//! #[derive(Clone)]
//! pub struct Counter {
//! #[ruby(get)]
//! count: i64,
//! step: i64,
//! }
//!
//! #[rubymethods]
//! impl Counter {
//! // `new` becomes `initialize`: `Stats::Counter.new(40, step: 2)`.
//! pub fn new(start: Option<i64>, #[ruby(keyword)] step: Option<i64>) -> Self {
//! Counter { count: start.unwrap_or(0), step: step.unwrap_or(1) }
//! }
//!
//! // `&mut self` is the struct inside the Ruby object.
//! pub fn tick(&mut self) -> Result<i64, String> {
//! self.count = self.count.checked_add(self.step).ok_or("counter overflow")?;
//! Ok(self.count)
//! }
//!
//! #[ruby(name = "to_s")]
//! pub fn describe(&self) -> String {
//! format!("#<Counter {}>", self.count)
//! }
//! }
//!
//! fn main() {
//! # VM::init();
//! Counter::define_ruby();
//!
//! let result = VM::eval("c = Stats::Counter.new(40, step: 2); c.tick; c.dup.to_s").unwrap();
//! assert_eq!(result.try_convert_to::<RString>().unwrap().to_str(), "#<Counter 42>");
//!
//! // A wrong argument is a `TypeError`; `Err` is raised after the
//! // method's Rust values are dropped.
//! let error = VM::eval("Stats::Counter.new('40')").unwrap_err();
//! assert!(Class::from_existing("TypeError").case_equals(&error));
//! }
//! ```
//!
//! # `#[rubyclass]`
//!
//! `#[rubyclass(path = "A::B")]` on a struct stores it in the Ruby objects of
//! class `A::B` (the path defaults to the struct's name). Its generated
//! `define_ruby()` defines the class, any modules in its path that don't
//! exist yet, its allocator, the field accessors, `initialize_copy`, and the
//! methods of its `#[rubymethods]` blocks.
//!
//! - **Borrows are checked.** The struct sits behind a borrow flag: if Ruby
//! code called from a method reaches the same object again, a conflicting
//! borrow (`&mut self` while borrowed, or `&self` while borrowed mutably)
//! raises a `RuntimeError` instead of creating aliasing references.
//! - **Ruby objects in fields are kept alive.** Each field whose type
//! implements [`Mark`] (Ruby types, and `Option`, `Vec`, `HashMap`, tuples,
//! … of them, and `#[derive(Mark)]` types) is marked for the GC and updated
//! after `GC.compact` (Ruby 2.7; Ruby 2.5 and 2.6 don't move objects).
//! `#[ruby(no_mark)]` skips a field;
//! `mark = path::to::fn` replaces all of it with a `fn(&Self)` that marks
//! with [`GC::mark`](../struct.GC.html#method.mark) (objects then never
//! move).
//! - **Ruby's object model.** `Class#new` allocates an uninitialized object
//! and calls `initialize`, which is the struct's constructor (a method
//! without a receiver named `new`, or marked `#[ruby(constructor)]`), so
//! Ruby subclasses can define `initialize` and call `super`. Using an
//! uninitialized object raises `TypeError`. `dup` and `clone` copy the
//! struct when it is `Clone` and raise `TypeError` otherwise.
//! `allocator = false` leaves the class without an allocator: objects then
//! come only from Rust.
//! - **Inheritance.** `extends = Parent` makes the class a subclass of
//! another `#[rubyclass]`; the struct holds the parent's struct in a field
//! marked `#[ruby(base)]`, and the parent's methods work on the child's
//! objects.
//! - **Accessors.** `#[ruby(get)]`, `#[ruby(set)]` (or both) on a field define
//! `name` and `name=`; `#[ruby(get, name = "label")]` renames them. The
//! getter returns a clone of the field.
//! - `size = path::to::fn` reports memory to `ObjectSpace.memsize_of`.
//!
//! # `#[rubymethods]`
//!
//! On an `impl` block of a `#[rubyclass]` struct, which stays plain Rust:
//!
//! - `&self` and `&mut self` methods are instance methods; methods without a
//! receiver are singleton methods (`def self.name`), except the
//! constructor, which is `initialize`.
//! - Positional parameters are `&T` or `T` (required) and `Option<&T>` or
//! `Option<T>` (optional, trailing; missing or `nil` is `None`), for Ruby
//! types (`&RString`, `Integer`, `&AnyObject`, …), Rust types (`i64`, `f64`,
//! `bool`, `String`, `&str`, `&[u8]`, [`Bytes`], `Vec<T>`, `HashMap<K, V>`,
//! …) and `#[rubyclass]` structs (`&T` or `&mut T`). A wrong count raises
//! `ArgumentError`, a wrong type `TypeError`, and an integer out of range
//! `RangeError`.
//! - `#[ruby(splat)] rest: Vec<T>` (or `Array`) takes the remaining
//! arguments; `#[ruby(keyword)] name: T` is a keyword argument (optional
//! when `T` is an `Option`); `#[ruby(block)] block: Proc` (or
//! `Option<Proc>`) is the block.
//! - The return type is anything [`IntoRubyObject`] (Ruby and Rust types,
//! `()`, `Option`, `Vec`, `HashMap`, tuples, `#[rubyclass]` structs), or a
//! `Result` of one whose `Err` is [`IntoException`] (`AnyException`,
//! `String`, `std::io::Error`, `Box<dyn Error>`, `#[rubyerror]` types).
//! - `#[ruby(name = "zero?")]` names the Ruby method; `#[ruby(skip)]` leaves
//! a method out; `#[ruby(private)]` and `#[ruby(protected)]` set its
//! visibility.
//! - `#[ruby(without_gvl)]` runs the method with Ruby's GVL released, so
//! other Ruby threads run meanwhile. Its parameters and result must be
//! [`WithoutGvl`] (plain Rust data), a `&self` receiver's struct must be
//! `Sync`, and it must not use Ruby.
//! - A struct can have up to eight `#[rubymethods]` blocks:
//! `#[rubymethods(part = 1)]` … `(part = 7)` for the ones after the first.
//!
//! Every generated method converts its arguments, takes its borrows, then
//! calls your method under `rb_protect`: a Ruby exception raised by Ruby code
//! your method calls is caught there, the borrows and converted arguments
//! are released, and the exception continues. Your own Rust values are only
//! dropped if you return `Err` instead (#159). A panic is raised as a
//! `RuntimeError`.
//!
//! Methods with only required positional parameters (and at most fifteen)
//! are defined with that arity, so Ruby checks the count and passes the
//! arguments without an array.
//!
//! # `#[rubymodule]`, `#[rubyfunction]`
//!
//! `#[rubymodule(path = "Greeter")]` on an inline `mod` defines its functions
//! as the module's singleton methods (`#[ruby(module_function)]` for a
//! module function), its `#[ruby(constant)]` constants as constants, and the
//! `#[rubyclass]` structs inside it, all from the module's generated
//! `define_ruby()`. `#[rubyfunction]` on a single function keeps it, and adds
//! a module of the same name holding `ruby`, the callback for
//! `def`/`def_self`.
//!
//! # `#[rubyerror]`
//!
//! `#[rubyerror(path = "Stats::Error", superclass = "StandardError")]` on an
//! error type that implements `Display` maps it to that Ruby exception
//! class; `#[ruby(path = "Stats::OverflowError")]` on an enum variant gives
//! the variant a subclass. Return it in `Err` from any method.
//!
//! # RBS
//!
//! `T::rbs()` on a `#[rubyclass]`, `#[rubymodule]` or `#[rubyerror]` type is
//! its RBS declaration, for writing `sig/*.rbs` files.
pub use ;
/// What generated code uses; not a stable API.