Where is the Rust intrinsic called "transmute" actually implemented? - rust

I'm trying to find the implementation for the Rust intrinsics, particularly the "transumte" intrinsic that takes one argument.
I've seen the following code in cast.rs, but as you can see, it merely delegates to some other implementation of transmute.
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
intrinsics::transmute(thing)
}
Where is the actual implementation for intrinsics, especially the transmute intrinsic?

cast::transmute delegates to intrinsics::transmute. There is a module called intrinsics (now in libcore), it contains extern bindings to several functions, including transmute. As you can see from the module documentation, implementation of intrinsics is said to be located in librustc/middle/trans/foreign.rs.
However, as far as I can see, actual implementation of intrinsics is present in librustc/middle/trans/intrinsic.rs. You can search for transmute, and you will find an arm in a really big match statement which looks like this:
"transmute" => {
let (in_type, out_type) = (*substs.substs.tps.get(0),
*substs.substs.tps.get(1));
let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type);
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
if in_type_size != out_type_size {
let sp = match ccx.tcx.map.get(ref_id.unwrap()) {
ast_map::NodeExpr(e) => e.span,
_ => fail!("transmute has non-expr arg"),
};
ccx.sess().span_fatal(sp,
format!("transmute called on types with different sizes: \
{intype} ({insize, plural, =1{# bit} other{# bits}}) to \
{outtype} ({outsize, plural, =1{# bit} other{# bits}})",
intype = ty_to_str(ccx.tcx(), in_type),
insize = in_type_size as uint,
outtype = ty_to_str(ccx.tcx(), out_type),
outsize = out_type_size as uint));
}
if !return_type_is_void(ccx, out_type) {
let llsrcval = get_param(decl, first_real_arg);
if type_is_immediate(ccx, in_type) {
match fcx.llretptr.get() {
Some(llretptr) => {
Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
RetVoid(bcx);
}
None => match (llintype.kind(), llouttype.kind()) {
(Pointer, other) | (other, Pointer) if other != Pointer => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
(Array, _) | (_, Array) | (Struct, _) | (_, Struct) => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
_ => {
let llbitcast = BitCast(bcx, llsrcval, llouttype);
Ret(bcx, llbitcast)
}
}
}
} else if type_is_immediate(ccx, out_type) {
let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
let ll_load = Load(bcx, llsrcptr);
Ret(bcx, ll_load);
} else {
// NB: Do not use a Load and Store here. This causes massive
// code bloat when `transmute` is used on large structural
// types.
let lldestptr = fcx.llretptr.get().unwrap();
let lldestptr = PointerCast(bcx, lldestptr, Type::i8p(ccx));
let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p(ccx));
let llsize = llsize_of(ccx, llintype);
call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
RetVoid(bcx);
};
} else {
RetVoid(bcx);
}
}
This seems to be code which generates code which will be inserted instead of a call to transmute. I'm no compiler expert, so please someone correct me if I'm wrong.

Related

Refactoring variable assignment thru if let block with Enum

I'm working with the code below, which works, but is clearly not a very clever or efficient way to write a value to res.
let mut res = "";
if let Video(n) = res_info { // res_info represents reference to &Settings type
if n.pixel_width > 1920{
res = "2160p";
}
else{
res = "1080p";
}
}
Printing res_info would yield the following:
Video(Video { pixel_width: 1920, pixel_height: 1080})
The following code seems to be close, however it's not assigning &str to res. I would much prefer a codeblock like this, in which res is only declared once.
let res = if let Video(n) = res_info {
if n.pixel_width > 1920 {
"2160p";
}
else{
"1080p";
}
};
As per the unit documentation
The semicolon ; can be used to discard the result of an expression at the end of a block, making the expression (and thus the block) evaluate to ()
Removing the semicolon should stop value from being discarded so the &str is resolved from the if blocks.
let res = if let Video(n) = res_info {
if n.pixel_width > 1920{
"2160p"
} else{
"1080p"
}
}else{
panic!("res_info is not a Video")
};
or with a match statement might be cleaner
let res = match res_info {
Video(n) if n.pixel_width > 1920 => "2160p",
Video(n) => "1080p",
_ => panic!("res_info is not a Video")
};

How to get argument of a variant?

Having these enums
pub enum Symbol {
X,
O,
}
pub enum CellContent {
Move(Symbol),
Empty,
}
and
let cell_content = CellContent::Move(Symbol::X);
how can I get the Symbol ? Of course if it's of variant Move(Symbol)
This doesn't work
if cell_0_0 == Move(a_symbol) {
return Some(a_symbol);
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
// code must go on to check further conditions
| I still have some problem with basic syntax of rust, so I'm experiencing making some basic programs
So question is
How to
check if my variable is a variant of Move(Symbol)
if yes return (a copy of) symbol
else do nothing, so code can go on and do more checks
?
Edit 1: Full (not working) code
pub fn some_one_win(&self) -> Option<Symbol> {
let cell_0_0: CellContent = self.table[0][0];
let cell_0_1: CellContent = self.table[0][1];
let cell_0_2: CellContent = self.table[0][2];
if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 {
match cell_0_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
let cell_1_0: CellContent = self.table[1][0];
let cell_1_1: CellContent = self.table[1][1];
let cell_1_2: CellContent = self.table[1][2];
if cell_1_0 == cell_1_1 && cell_1_0 == cell_1_2 {
match cell_1_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
... and so on ..
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
You can do that, if you get the syntax right:
match cell_0_0 {
CellContent::Move(symbol) => {
return Some(symbol);
}
_ => {} // do nothing
}
But as PitaJ mentioned, when there’s only one pattern plus _, the if let construct is usually a cleaner alternative:
if let CellContent::Move(symbol) = cell_0_0 {
return Some(symbol);
}

Which is the equivalent of "BLOCKCHAIN_INTERFACE 3.1.0" in the near-sdk 4.0.0-pre.4?

In the near-sdk 3.1.0 we use the BLOCKCHAIN_INTERFACE to make a Dao remote-upgrade with the next method:
#[cfg(target_arch = "wasm32")]
pub fn upgrade(self) {
// assert!(env::predecessor_account_id() == self.minter_account_id);
//input is code:<Vec<u8> on REGISTER 0
//log!("bytes.length {}", code.unwrap().len());
const GAS_FOR_UPGRADE: u64 = 20 * TGAS; //gas occupied by this fn
const BLOCKCHAIN_INTERFACE_NOT_SET_ERR: &str = "Blockchain interface not set.";
//after upgrade we call *pub fn migrate()* on the NEW CODE
let current_id = env::current_account_id().into_bytes();
let migrate_method_name = "migrate".as_bytes().to_vec();
let attached_gas = env::prepaid_gas() - env::used_gas() - GAS_FOR_UPGRADE;
unsafe {
BLOCKCHAIN_INTERFACE.with(|b| {
// Load input (new contract code) into register 0
b.borrow()
.as_ref()
.expect(BLOCKCHAIN_INTERFACE_NOT_SET_ERR)
.input(0);
//prepare self-call promise
let promise_id = b
.borrow()
.as_ref()
.expect(BLOCKCHAIN_INTERFACE_NOT_SET_ERR)
.promise_batch_create(current_id.len() as _, current_id.as_ptr() as _);
//1st action, deploy/upgrade code (takes code from register 0)
b.borrow()
.as_ref()
.expect(BLOCKCHAIN_INTERFACE_NOT_SET_ERR)
.promise_batch_action_deploy_contract(promise_id, u64::MAX as _, 0);
// 2nd action, schedule a call to "migrate()".
// Will execute on the **new code**
b.borrow()
.as_ref()
.expect(BLOCKCHAIN_INTERFACE_NOT_SET_ERR)
.promise_batch_action_function_call(
promise_id,
migrate_method_name.len() as _,
migrate_method_name.as_ptr() as _,
0 as _,
0 as _,
0 as _,
attached_gas,
);
});
}
}
To use the BLOCKCHAIN_INTERFACE I use this import:
use near_sdk::env::BLOCKCHAIN_INTERFACE;
In the near-sdk 4.0.0-pre.4 I can't use this interface to make the remote-upgrade, how I can solve it?
I read something about the MockedBlockchain, but I can't use it, the import doesn't exist or the methods are private and also says that it's only for #test
Yes, so that blockchain interface was removed completely so there is no need to go through that at all anymore. For all methods, you can just use near_sdk::sys to call each low level method. Here is the contract code migrated:
#[cfg(target_arch = "wasm32")]
pub fn upgrade(self) {
use near_sdk::sys;
// assert!(env::predecessor_account_id() == self.minter_account_id);
//input is code:<Vec<u8> on REGISTER 0
//log!("bytes.length {}", code.unwrap().len());
const GAS_FOR_UPGRADE: u64 = 20 * TGAS; //gas occupied by this fn
const BLOCKCHAIN_INTERFACE_NOT_SET_ERR: &str = "Blockchain interface not set.";
//after upgrade we call *pub fn migrate()* on the NEW CODE
let current_id = env::current_account_id().into_bytes();
let migrate_method_name = "migrate".as_bytes().to_vec();
let attached_gas = env::prepaid_gas() - env::used_gas() - GAS_FOR_UPGRADE;
unsafe {
// Load input (new contract code) into register 0
sys::input(0);
//prepare self-call promise
let promise_id =
sys::promise_batch_create(current_id.len() as _, current_id.as_ptr() as _);
//1st action, deploy/upgrade code (takes code from register 0)
sys::promise_batch_action_deploy_contract(promise_id, u64::MAX as _, 0);
// 2nd action, schedule a call to "migrate()".
// Will execute on the **new code**
sys::promise_batch_action_function_call(
promise_id,
migrate_method_name.len() as _,
migrate_method_name.as_ptr() as _,
0 as _,
0 as _,
0 as _,
attached_gas,
);
}
}
Let me know if this solves your problem completely or if there is anything else I can help with :)

Build variable length arguments array for #call

I've recently started learning Zig.
As a little project I wanted to implement a small QuickCheck [1] style helper library for writing randomized tests.
However, I can't figure out how to write a generic way to call a function with an arbitrary number of arguments.
Here's a simplified version that can test functions with two arguments:
const std = #import("std");
const Prng = std.rand.DefaultPrng;
const Random = std.rand.Random;
const expect = std.testing.expect;
// the thing we want to test
fn some_property(a: u64, b: u64) !void {
var tmp: u64 = undefined;
var c1 = #addWithOverflow(u64, a, b, &tmp);
var c2 = #addWithOverflow(u64, a, b, &tmp);
expect(c1 == c2);
}
// helper for generating random arguments for the function under test
fn gen(comptime T: ?type, rnd: Random) (T orelse undefined) {
switch (T orelse undefined) {
u64 => return rnd.int(u64),
f64 => return rnd.float(f64),
else => #compileError("unsupported type"),
}
}
/// tests if 'property' holds.
fn for_all(property: anytype) !void {
var rnd = Prng.init(0);
const arg_types = #typeInfo(#TypeOf(property)).Fn.args;
var i: usize = 0;
while (i < 100) {
var a = gen(arg_types[0].arg_type, rnd.random());
var b = gen(arg_types[1].arg_type, rnd.random());
var args = .{a, b}; // <-- how do I build args for functions with any number of arguments?
try #call(.{}, property, args);
i += 1;
}
}
test "test" {
try for_all(some_property);
}
I've tried a few different things, but I can't figure out how to get the above code to work for functions with any number of arguments.
Things I've tried:
Make args an array and fill it with an inline for loop. Doesn't work since []anytype is not a valid type.
Use a bit of comptime magic to build a struct type whose fields hold the arguments for #call. This hits a TODO in the compiler: error: TODO: struct args.
Write generic functions that return an appropriate argument tuple call. I don't really like this one, since you need one function for every arity you want to support. But it doesn't seem to work anyway since antype is not a valid return type.
I'm on Zig 0.9.1.
Any insight would be appreciated.
[1] https://hackage.haskell.org/package/QuickCheck
This can be done with std.meta.ArgsTuple (defined in this file of the zig standard library)
const Args = std.meta.ArgsTuple(#TypeOf(property));
var i: usize = 0;
while (i < 1000) : (i += 1) {
var args: Args = undefined;
inline for (std.meta.fields(Args)) |field, index| {
args[index] = gen(field.field_type, rnd.random());
}
try #call(.{}, property, args);
}
The way this works internally is it constructs a tuple type with #Type(). We can then fill it with values and use it to call the function.

How do a pass a database variable to a function in Rust?

I'm just starting to look at Rust. I wanted to experiment with a database, and found the sqlite repo which is good to have to experiment with.
I would like to know the "correct" way to pass the sqlite database variable to a function. The error messages that I was initially getting from the compiler appeared to indicate that when I passed the Db variable from main() to the function, it was gone, so I returned it. Although this appears to work, it doesn't seem to me that it would be the normal way. While I'm not a believer in a large number of Global variables, I attempted to create a Global variables, but I couldn't discover how to do that.
Below is the test program. Please note that I am not yet using the Rust naming conventions, but it is very-early days
The main lines in question are :
oDb1 = fCreateTable(oDb1);
fn fCreateTable(oDb1:sqlite::database::Database) -> sqlite::database::Database {
and what is the alternative and why is it necessary (in this instance) to return it?
Example program:
extern mod sqlite;
fn main() {
let mut oDb1:sqlite::database::Database;
oDb1 = fOpenDb();
oDb1 = fCreateTable(oDb1) ;
let mut iInsertTot: int = 0;
while iInsertTot < 25 {
let oDbExec = oDb1.exec("INSERT INTO test (sname, iborn) VALUES ('xxxxx', 1973)");
if (! oDbExec.is_ok()) {
fail!(fmt!("Insert Nr. %d Failed!", iInsertTot+1));
}
iInsertTot += 1;
}
println (fmt!("Inserts completed = %d", iInsertTot));
}
fn fOpenDb() -> sqlite::database::Database {
let oDbOpen = sqlite::open("test.db");
if oDbOpen.is_err() {
fail!(fmt!("Error opening test.db: %?", oDbOpen));
}
println(fmt!("Database Open OK? %?", oDbOpen.is_ok()));
oDbOpen.unwrap()
}
fn fCreateTable(oDb1:sqlite::database::Database) -> sqlite::database::Database {
let mut oDbExec = oDb1.exec("drop table if exists test");
println(fmt!("Drop Table OK? %?", oDbExec.is_ok()));
if (!oDbExec.is_ok()) {
fail!("Drop-table failed");
}
oDbExec = oDb1.exec("CREATE TABLE test (ikey INTEGER PRIMARY KEY not null,
sname text, iborn int)");
println(fmt!("Create OK? %?", oDbExec.is_ok()));
if !oDbExec.is_ok() {
fail!("Create Table failed");
}
oDb1
}
sqlite::database::Database implements Drop, meaning it has a destructor, meaning it is never copied and always moved: fCreateTable(oDb1) moves the database object out of oDb1: Now there's nothing left in oDb1! Of course, you can put back something. For example, when you return the database from fCreateTable, you again move - back into fCreateTable.
But this is a silly dance. Just don't move the database in the first place, borrowed a pointer to it:
fn main() {
let oDb1 = fOpenDb();
fCreateTable(&oDb1);
...
}
fn fCreateTable(oDb1: &sqlite::database::Database) {
...
}

Resources