#[repr(transparent)]
pub struct Value<'scope, 'data>(_, _, _);
Expand description

See the [module-level documentation] for more information.

A Value is a wrapper around a non-null pointer to some data owned by the Julia garbage collector, it has two lifetimes: 'scope and 'data. The first of these ensures that a Value can only be used while it’s rooted, the second accounts for data borrowed from Rust. The only way to borrow data from Rust is to create an Julia array that borrows its contents by calling Array::from_slice; if a Julia function is called with such an array as an argument the result will inherit the second lifetime of the borrowed data to ensure that such a Value can only be used while the borrow is active.

Implementations

Create new Values

Several methods are available to create new values. The simplest of these is Value::new, which can be used to convert relatively simple data from Rust to Julia. Data that can be converted this way must implement IntoJulia, which is the case for types like the primitive number types. This trait is also automatically derived by JlrsReflect.jl for types that are trivially guaranteed to be bits-types: the type must have no type parameters, no unions, and all fields must be immutable bits-types themselves.

Create a new Julia value, any type that implements IntoJulia can be converted using this function.

Create a new Julia value, any type that implements IntoJulia can be converted using this function. Unlike Value::new this method doesn’t root the allocated value.

Create a new named tuple, you should use the named_tuple macro rather than this method.

Apply the given types to self.

If self is the DataType anytuple_type, calling this method will return a new tuple type with the given types as its field types. If it is the DataType uniontype_type, calling this method is equivalent to calling Union::new. If the value is a UnionAll, the given types will be applied and the resulting type is returned.

If the types can’t be applied to self this methods catches and returns the exception.

Apply the given types to self.

If self is the DataType anytuple_type, calling this method will return a new tuple type with the given types as its field types. If it is the DataType uniontype_type, calling this method is equivalent to calling Union::new. If the value is a UnionAll, the given types will be applied and the resulting type is returned.

If an exception is thrown it isn’t caught

Safety: an exception must not be thrown if this method is called from a ccalled function.

Type information

Every value is guaranteed to have a DataType. This contains all of the value’s type information.

Returns the DataType of this value.

Returns the name of this value’s DataType as a string slice.

Type checking

Many properties of Julia types can be checked, including whether instances of the type are mutable, if the value is an array, and so on. The method Value::is can be used to perform these checks. All these checks implement the Typecheck trait. If the type that implements this trait also implements ValidLayout, the typecheck indicates whether or not the value can be cast to or unboxed as that type.

Performs the given typecheck:

julia.scope(|_global, mut frame| {
    let i = Value::new(&mut frame, 2u64)?;
    assert!(i.is::<u64>());
    Ok(())
}).unwrap();

A full list of supported checks can be found here.

Returns true if the value is an array with elements of type T.

Returns true if self is a subtype of sup.

Returns true if self is the type of a DataType, UnionAll, Union, or Union{} (the bottom type).

Returns true if the value is a type, ie a DataType, UnionAll, Union, or Union{} (the bottom type).

Returns true if self is of type ty.

Lifetime management

Values have two lifetimes, 'scope and 'data. The first ensures that a value can only be used while it’s rooted, the second ensures that values that (might) borrow array data from Rust are also restricted by the lifetime of that borrow. This second restriction can be relaxed with Value::assume_owned if it doesn’t borrow any data from Rust.

If you call a Julia function with one or more borrowed arrays as arguments, its result can only be used when all the borrows are active. If this result doesn’t contain any borrowed data this function can be used to relax its second lifetime to 'static.

Safety: The value must not contain any data borrowed from Rust.

Use the Output to extend the lifetime of this data.

Conversions

There are two ways to convert a Value to some other type. The first is casting, which is used to convert a Value to the appropriate pointer wrapper type. For example, if the Value is a Julia array it can be cast to Array. Because this only involves a pointer cast it’s always possible to convert a wrapper to a Value by calling Wrapper::as_value. The second way is unboxing, which is used to copy the data the Value points to to Rust. If a Value is a UInt8, it can be unboxed as a u8. By default, jlrs can unbox the default primitive types and Julia strings, but the Unbox trait can be implemented for other types. It’s recommended that you use JlrsReflect.jl to do so. Unlike casting, unboxing dereferences the pointer. As a result it loses its header, so an unboxed value can’t be used as a Value again without reallocating it.

Cast the value to a pointer wrapper type T. Returns an error if the conversion is invalid.

Cast the value to a pointer wrapper type T without checking if this conversion is valid.

Safety: You must guarantee self.is::<T>() would have returned true.

Unbox the contents of the value as the output type associated with T. Returns an error if the layout of T::Output is incompatible with the layout of the type in Julia.

Unbox the contents of the value as the output type associated with T without checking if the layout of T::Output is compatible with the layout of the type in Julia.

Safety: You must guarantee self.is::<T>() would have returned true.

Returns a pointer to the data, this is useful when the output type of Unbox is different than the implementation type and you have to write a custom unboxing function. It’s your responsibility this pointer is used correctly.

Fields

Most Julia values have fields. For example, if the value is an instance of this struct:

struct Example
   fielda
   fieldb::UInt32
end

it will have two fields, fielda and fieldb. The first field is a pointer field, the second is stored inline as a u32. It’s possible to safely access the raw contents of these fields with the method Value::field_accessor. The first field can be accessed as a ValueRef, the second as a u32.

Returns the field names of this value as a slice of Symbols.

Returns the number of fields the underlying Julia value has.

Returns an accessor to access the contents of this value without allocating temporary Julia data.

Roots the field at index idx if it exists and returns it, or a JlrsError::AccessError if the index is out of bounds.

Returns the field at index idx if it’s a pointer field.

If the field doesn’t exist or if the field can’t be referenced because its data is stored inline, a JlrsError::AccessError is returned.

Returns the field at index idx if it exists as a ValueRef. If the field is an inline field a new value is allocated which is left unrooted.

If the field doesn’t exist JlrsError::OutOfBoundsField is returned.

Roots the field with the name field_name if it exists and returns it, or a JlrsError::AccessError if there’s no field with that name.

Returns the field with the name field_name if it’s a pointer field.

If the field doesn’t exist or if the field can’t be referenced because its data is stored inline, a JlrsError::AccessError is returned.

Returns the field with the name field_name if it exists. If the field is an inline field a new value is allocated which is left unrooted.

If the field doesn’t exist a JlrsError::AccessError is returned.

Set the value of the field at idx. If Julia throws an exception it’s caught, rooted in the frame, and returned. If the index is out of bounds or the value is not a subtype of the field an error is returned,

Safety: Mutating things that should absolutely not be mutated, like the fields of a DataType, is not prevented.

Set the value of the field at idx. If Julia throws an exception it’s caught and returned but not rooted. If the index is out of bounds or the value is not a subtype of the field an error is returned,

Safety: Mutating things that should absolutely not be mutated, like the fields of a DataType, is not prevented.

Set the value of the field at idx. If Julia throws an exception the process aborts.

Safety: this method doesn’t check if the type of the value is a subtype of the field’s type. Mutating things that should absolutely not be mutated, like the fields of a DataType, is also not prevented.

Set the value of the field with the name field_name. If Julia throws an exception it’s caught, rooted in the frame, and returned. If there’s no field with the given name or the value is not a subtype of the field an error is returned.

Safety: Mutating things that should absolutely not be mutated, like the fields of a DataType, is not prevented.

Set the value of the field with the name field_name. If Julia throws an exception it’s caught, and returned but not rooted. If there’s no field with the given name or the value is not a subtype of the field an error is returned.

Safety: Mutating things that should absolutely not be mutated, like the fields of a DataType, is not prevented.

Set the value of the field with the name field_name. If Julia throws an exception the process aborts. If there’s no field with the given name an error is returned.

Safety: this method doesn’t check if the type of the value is a subtype of the field’s type. Mutating things that should absolutely not be mutated, like the fields of a DataType, is also not prevented.

Evaluate Julia code

The easiest way to call Julia from Rust is by evaluating some Julia code directly. This can be used to call simple functions without any arguments provided from Rust and to execute using-statements.

Execute a Julia command cmd, for example Value::eval_string(&mut *frame, "sqrt(2)") or Value::eval_string(&mut *frame, "using LinearAlgebra").

Safety: The command can’t be checked for correctness, nothing prevents you from causing a segmentation fault with a command like unsafe_load(Ptr{Float64}(C_NULL)).

Execute a Julia command cmd. This is equivalent to Value::eval_string, but uses a null-terminated string.

Safety: The command can’t be checked for correctness, nothing prevents you from causing a segmentation fault with a command like unsafe_load(Ptr{Float64}(C_NULL)).

Calls include in the Main module in Julia, which evaluates the file’s contents in that module. This has the same effect as calling include in the Julia REPL.

Safety: The content of the file can’t be checked for correctness, nothing prevents you from causing a segmentation fault with code like unsafe_load(Ptr{Float64}(C_NULL)).

Returns the object id of this value.

Returns true if self and other are equal.

Add a finalizer f to this value. The finalizer must be a Julia function, it will be called when this value is about to be freed by the garbage collector.

Safety: the finalizer must be compatible with the data.

Add a finalizer f to this value. The finalizer must be an extern "C" function that takes one argument, the value as a void pointer.

Safety: the finalizer must be compatible with the data.

Union{}.

StackOverflowError.

OutOfMemoryError.

ReadOnlyMemoryError.

DivideError.

UndefRefError.

InterruptException.

An empty `Array{Any, 1}.

An empty immutable String, “”.

Array{UInt8, 1}

Array{Any, 1}

Array{Symbol, 1}

Array{Int32, 1}

The empty tuple, ().

The instance of true.

The instance of false.

The instance of Nothing, nothing.

The handle to stdout as a Julia value.

The handle to stderr as a Julia value.

Trait Implementations

Call a function with no arguments and root the result in scope. Read more

Call a function with one argument and root the result in scope. Read more

Call a function with two arguments and root the result in scope. Read more

Call a function with three arguments and root the result in scope. Read more

Call a function with an arbitrary number arguments and root the result in scope. Read more

Call a function with no arguments without rooting the result. Read more

Call a function with one argument without rooting the result. Read more

Call a function with two arguments without rooting the result. Read more

Call a function with three arguments without rooting the result. Read more

Call a function with an abitrary number of arguments without rooting the result. Read more

Call a function on another thread with the given arguments. This method uses Base.Threads.@spawn to call the given function on another thread but return immediately. While awaiting the result the async runtime can work on other tasks, the current task resumes after the function call on the other thread completes. Read more

Does the same thing as CallAsync::call_async, but the task is returned rather than an awaitable Future. This method should only be called in PersistentTask::init, otherwise it’s not guaranteed this task can make progress. Read more

Call a function with the given arguments in an @async block. Like call_async, the function is not called on the main thread, but on a separate thread that handles all tasks created by this method. This method should only be used with functions that do very little computational work but mostly spend their time waiting on IO. Read more

Does the same thing as CallAsync::call_async_local, but the task is returned rather than an awaitable Future. This method should only be called in PersistentTask::init, otherwise it’s not guaranteed this task can make progress. Read more

Call a function with the given arguments in an @async block. The task is scheduled on the main thread. This method should only be used with functions that must run on the main thread. The runtime is blocked while this task is active. Read more

Does the same thing as CallAsync::call_async_main, but the task is returned rather than an awaitable Future. This method should only be called in PersistentTask::init, otherwise it’s not guaranteed this task can make progress. Read more

Returns a copy of the value. Read more

Performs copy-assignment from source. Read more

Formats the value using the given formatter. Read more

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

This method tests for self and other values to be equal, and is used by ==. Read more

This method tests for !=.

Provide keyword arguments to the function. The keyword arguments must be a NamedTuple. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more

Immutably borrows from an owned value. Read more

Mutably borrows from an owned value. Read more

Returns the argument unchanged.

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

The resulting type after obtaining ownership.

Creates owned data from borrowed data, usually by cloning. Read more

Uses borrowed data to replace owned data, usually by cloning. Read more

The type returned in the event of a conversion error.

Performs the conversion.

The type returned in the event of a conversion error.

Performs the conversion.

Convert the wrapper to a Ref.

Convert the wrapper to a Value.

Convert the wrapper to its display string, i.e. the string that is shown when calling Base.show. Read more

Convert the wrapper to its error string, i.e. the string that is shown when calling Base.showerror. This string can contain ANSI color codes if this is enabled by calling Julia::error_color, AsyncJulia::error_color, or AsyncJulia::try_error_color, . Read more

Convert the wrapper to its display string, i.e. the string that is shown by calling Base.display, or some default value. Read more

Convert the wrapper to its error string, i.e. the string that is shown when this value is thrown as an exception, or some default value. Read more