Remove coercion docs for now

I'll try to bring this back ASAP. However they are currently quite outdated and causing confusion.
This commit is contained in:
Godfrey Chan 2017-10-17 23:33:44 -07:00 committed by GitHub
parent fed2e7889d
commit 4216a3a758
1 changed files with 0 additions and 87 deletions

View File

@ -82,90 +82,3 @@ hello
hello world
=> nil
```
## Coercions
When you define a method in Helix using `def`, you can specify any Rust type in its type signature.
Under the hood, Helix will automatically coerce the Ruby type to the specified Rust type, doing appropriate type checks before passing the values into Rust.
```rust
ruby! {
class Console {
def log(&self, string: &str) {
println!("LOG: {}", string);
}
}
}
```
```shell
$ irb
>> require "console"
>> Console.new.log({})
TypeError: No implicit coercion of {} into String
from (irb):2:in `log'
from (irb):2
from /Users/ykatz/.rvm/rubies/ruby-2.3.0/bin/irb:11:in `<main>'
```
### The Helix Coercion Protocol
Under the hood, Helix does not hardcode all possible coercions from Ruby into Rust. Instead, it defines a two-part protocol that any crate can implement to define coercions from Ruby values into their types.
```rust
pub trait UncheckedValue<T> {
fn to_checked(self) -> CheckResult<T>;
}
pub trait ToRust<T> {
fn to_rust(self) -> T;
}
```
Implementations of these traits use these concrete types:
```rust
pub type CheckResult<T> = Result<CheckedValue<T>, String /* error */>;
pub struct CheckedValue<T> {
pub inner: VALUE;
// other private fields
}
impl<T> CheckedValue<T> {
// instantiating a CheckedValue<T> is an assertion that the follow-up
// call to `to_rust` is safe.
pub unsafe fn new(inner: VALUE) -> CheckedValue<T>;
}
```
For reference, here is the implementation of the coercion from a Ruby `String` to Rust `String`.
```rust
impl UncheckedValue<String> for VALUE {
fn to_checked(self) -> CheckResult<String> {
// check whether the VALUE is actually a String
if unsafe { sys::RB_TYPE_P(self, sys::T_STRING) } {
// assert that we can guarantee that to_rust() can return a Rust String safely
Ok(unsafe { CheckedValue::<String>::new(self) })
} else {
let val = unsafe { CheckedValue::<String>::new(sys::rb_inspect(self)) };
Err(format!("No implicit conversion of {} into String", val.to_rust()))
}
}
}
impl ToRust<String> for CheckedValue<String> {
fn to_rust(self) -> String {
// we're sure that these calls are safe, because we already went through the type
// checking protocol in VALUE.to_checked().
let size = unsafe { sys::RSTRING_LEN(self.inner) };
let ptr = unsafe { sys::RSTRING_PTR(self.inner) };
let slice = unsafe { std::slice::from_raw_parts(ptr as *const u8, size as usize) };
unsafe { std::str::from_utf8_unchecked(slice) }.to_string()
}
}
```
This protocol allows us to fully type check a method's arguments before starting any of the coercions. It happens automatically based on the type signature you use in your Rust method `def`.