Obsah
1. Předávání struktur mezi Rustem a céčkovou knihovnou
3. Céčková část příkladu – definice struktury a funkce akceptující tuto strukturu
4. Volání céčkové funkce z Rustu s předáním struktury
5. Překlad a spuštění prvního příkladu
6. Problematika zarovnání prvků ve struktuře a „výplní“ mezi prvky
7. Změna pořadí prvků struktury
8. Překlad a spuštění druhého příkladu
9. Export binární podoby struktury
10. Předání struktury odkazem (přes ukazatel)
12. Část aplikace naprogramovaná v Rustu
14. Modifikace prvků struktury v nativním kódu
16. Repositář s demonstračními příklady
1. Předávání struktur mezi Rustem a céčkovou knihovnou
V programovacím jazyku C je možné používat primitivní numerické datové typy, ukazatele, homogenní datovou strukturu (neboli pole), unie, bitová pole a taktéž záznamy, které jsou v céčku pojmenovány struct, takže se jim běžně říká i struktury. Tyto složené datové typy jsou podporovány i Rustem, takže vzniká zcela logická otázka, do jaké míry je možné při komunikaci mezi céčkem a Rustem záznamy/struktury používat. Ve skutečnosti je tato operace podporována a je velmi často používána – záznamy je možné předávat jak hodnotou, tak i odkazem (neboli přes ukazatel). Dnes si ukážeme některá úskalí použití záznamů, protože při komunikaci mezi Rustem a C je samozřejmě nutné zaručit, že se budou používat shodné typy prvků, stejný způsob zarovnání prvků atd.
Poznámka: komunikace s využitím bitových polí a unií je složitější a setkáme se s ní méně často.
2. Vytvoření nového projektu
Podobně jako minule, i dnes budeme používat pro správu projektů (překlad, slinkování, spuštění, otestování) nástroj Cargo. Zkusme si nejprve vytvořit prázdný projekt spravovaný systémem Cargo. Projekt bude sloužit k vytvoření spustitelné binární aplikace, a proto musíme použít přepínač –bin:
$ cargo new --bin ffi_project1
Po spuštění předchozího příkazu získáme následující adresářovou strukturu projektu:
. ├── Cargo.toml └── src └── main.rs
Do projektu přidáme soubor build.rs:
// balicek gcc zajisti preklad a vytvoreni knihovny za nas extern crate gcc; fn main() { // preklad a vytvoreni knihovny gcc::compile_library("libffi3.a", >["src/ffi3.c"]); }
Projektový soubor nepatrně upravíme:
[package] name = "ffi_project3" version = "0.1.0" authors = ["Pavel Tisnovsky <ptisnovs@redhat.com>"] build = "build.rs" [dependencies] [build-dependencies] gcc = "0.3"
A přidáme (příkazem touch) prázdný zdrojový soubor psaný v céčku:
$ touch src/ffi3.c
Výsledkem by měla být tato adresářová struktura:
. ├── build.rs ├── Cargo.lock ├── Cargo.toml └── src ├── ffi3.c └── main.rs
3. Céčková část příkladu – definice struktury a funkce akceptující tuto strukturu
Podívejme se nejprve na céčkovou část celého projektu, protože zde by programátory nemělo prakticky nic překvapit :-). Nejprve definujeme strukturu s přesným popisem datových typů včetně jejich šířky, tj. nepoužíváme jen char nebo int, ale explicitně uint8_t, int32_t atd. (pokud použijete int apod., bude problematické takový projekt spustit na jiných platformách):
typedef struct { uint8_t a; uint8_t b; uint8_t c; int32_t d; int32_t e; float f; } test_struct;
Následně je definována funkce, která po svém zavolání vypíše velikost předané struktury (ta je známa v době překladu) a její prvky. Povšimněte si, že této funkci skutečně předáváme celou strukturu, což nemusí být ve všech případech žádoucí chování (struktury mohou být poměrně rozsáhlé):
void print_struct(test_struct s) { printf("sizeof(test_struct) = %lu bytes\n", sizeof(s)); printf("a = %d\n", s.a); printf("b = %d\n", s.b); printf("c = %d\n", s.c); printf("d = %d\n", s.d); printf("e = %d\n", s.e); printf("f = %f\n", s.f); }
Úplný zdrojový kód céčkové části vypadá takto:
#include <stdint.h> #include <stdio.h> typedef struct { uint8_t a; uint8_t b; uint8_t c; int32_t d; int32_t e; float f; } test_struct; void print_struct(test_struct s) { printf("sizeof(test_struct) = %lu bytes\n", sizeof(s)); printf("a = %d\n", s.a); printf("b = %d\n", s.b); printf("c = %d\n", s.c); printf("d = %d\n", s.d); printf("e = %d\n", s.e); printf("f = %f\n", s.f); }
4. Volání céčkové funkce z Rustu s předáním struktury
V části naprogramované v Rustu je nutné nejprve deklarovat datovou strukturu takovým způsobem, aby přesně odpovídala céčkové části. Pro tento účel je nutné použít #[repr©], protože překladač Rustu musí uspořádat prvky struktury takovým způsobem, aby byla struktura bitově kompatibilní s céčkem (bitové obrazy struktury musí být naprosto shodné). Samozřejmě je také nutné dodržet pořadí prvků (na druhou stranu se může pojmenování prvků lišit):
#[repr(C)] struct TestStruct { a: u8, b: u8, c: u8, d: i32, e: i32, f: f32 }
V další části kódu musíme provést deklaraci externí (nativní) funkce napsané v céčku. Povšimněte si, že hlavička funkce přesně odpovídá konvencím Rustu (typ parametru, návratová hodnota):
extern { fn print_struct(s:TestStruct) -> (); }
Tuto funkci voláme opět v bloku unsafe:
let s : TestStruct = TestStruct{a:1, b:255, c:42, d:10000, e:-10000, f:3.14}; unsafe { print_struct(s); }
V programu dále strukturu vytvoříme a následně vypíšeme její velikost, a to konkrétně funkcí mem::size_of(), která velikost zjistí z generického typu:
use std::mem; let s : TestStruct = TestStruct{a:1, b:255, c:42, d:10000, e:-10000, f:3.14}; println!("sizeof on Rust side = {} bytes", mem::size_of::<TestStruct>());
Úplný zdrojový kód části psané v Rustu tedy bude vypadat následovně:
use std::mem; #[repr(C)] struct TestStruct { a: u8, b: u8, c: u8, d: i32, e: i32, f: f32 } extern { fn print_struct(s:TestStruct) -> (); } fn main() { let s : TestStruct = TestStruct{a:1, b:255, c:42, d:10000, e:-10000, f:3.14}; println!("sizeof on Rust side = {} bytes", mem::size_of::<TestStruct>()); unsafe { print_struct(s); } }
5. Překlad a spuštění příkladu
Vzhledem k tomu, že je celý projekt spravován nástrojem Cargo, je jeho překlad a slinkování jednoduché, což už ostatně známe z předchozích částí tohoto seriálu:
$ cargo build Compiling gcc v0.3.50 Compiling ffi_project3 v0.1.0 (file:///home/tester/ffi_project3) Finished debug [unoptimized + debuginfo] target(s) in 3.42 secs
I pro spuštění projektu použijeme nástroj Cargo. Měl by se vypsat následující text:
$ cargo run Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/ffi_project3` sizeof on Rust side = 16 bytes sizeof(test_struct) = 16 bytes a = 1 b = 255 c = 42 d = 10000 e = -10000 f = 3.140000
Poznámka: na architekturách odlišných od x86–64 se může lišit velikost struktury hlášené jak céčkovou částí, tak i částí psanou v Rustu. Stále by však měly být obě velikosti shodné (pokud nebudou shodné, budou se velmi pravděpodobně lišit i hodnoty přečtené v céčkové části).
6. Problematika zarovnání prvků ve struktuře a „výplní“ mezi prvky
Pokud jste se pečlivě podívali na výstup vypsaný předchozím projektem, asi jste si všimli, že datová struktura má hlášenou velikost 16 bajtů a nikoli pouze 15 bajtů, jak by se mohlo zdát při pouhém součtu velikostí jednotlivých prvků:
a: u8, 1 bajt b: u8, 1 bajt c: u8, 1 bajt d: i32, 4 bajty e: i32, 4 bajty f: f32 4 bajty celkem: 15 bajtů
Ve skutečnosti totiž na většině v současnosti používaných architektur mikroprocesorů (snad jen s výjimkou osmibitových mikrořadičů) mohou mezi prvky struktury vznikat volná místa, která sice zbytečně zabírají paměť, ovšem umožňují, aby se k prvkům struktury o velikosti slov přistupovalo mnohem rychleji, protože tyto prvky budou takzvaně zarovnány (aligned). To znamená, že prvky budou například umístěny na adresách dělitelných čtyřmi, osmi atd. (v závislosti na platformě a architektuře procesoru, například na x86 bude zarovnání většinou odpovídat šířce ukládaného slova). Bajty mezi prvky, které nejsou použity, se nazývají padding bytes:
a: u8, 1 bajt b: u8, 1 bajt c: u8, 1 bajt xxx 1 bajt - výplň (padding) d: i32, 4 bajty e: i32, 4 bajty f: f32 4 bajty celkem: 16 bajtů
Na jiných architekturách může být způsob zarovnání odlišný a některé překladače ho umožňují zcela vypnout. V případě GCC je možné použít __attribute__((__packed__)) atd. To znamená, že další příklad po překladu pomocí GCC a spuštění vypíše 16 bajtů a 15 bajtů:
#include <stdint.h> #include <stdio.h> typedef struct { uint8_t a; uint8_t b; uint8_t c; int32_t d; int32_t e; float f; } test_struct1; typedef struct __attribute__((__packed__)) { uint8_t a; uint8_t b; uint8_t c; int32_t d; int32_t e; float f; } test_struct2; int main(void) { printf("sizeof(test_struct1) = %lu bytes\n", sizeof(test_struct1)); printf("sizeof(test_struct2) = %lu bytes\n", sizeof(test_struct2)); return 0; }
7. Změna pořadí prvků struktury
Zkusme si nyní prohodit pořadí prvků ve struktuře. Namísto uspořádání:
typedef struct { uint8_t a; uint8_t b; uint8_t c; int32_t d; int32_t e; float f; } test_struct;
Použijeme strukturu, v níž je vždy mezi prvky se šířkou čtyři bajty vložen prvek jednobajtový:
typedef struct { uint8_t a; int32_t b; uint8_t c; int32_t d; uint8_t e; float f; } test_struct;
Upravená céčková část programu vypadá takto:
#include <stdint.h> #include <stdio.h> typedef struct { uint8_t a; int32_t b; uint8_t c; int32_t d; uint8_t e; float f; } test_struct; void print_struct(test_struct s) { printf("sizeof(test_struct) = %lu bytes\n", sizeof(s)); printf("a = %d\n", s.a); printf("b = %d\n", s.b); printf("c = %d\n", s.c); printf("d = %d\n", s.d); printf("e = %d\n", s.e); printf("f = %f\n", s.f); }
Část psaná v Rustu samozřejmě musí reflektovat všechny změny ve struktuře (ostatně – sami si vyzkoušejte, co se stane, když tuto část nezměníte):
use std::mem; #[repr(C)] struct TestStruct { a: u8, b: i32, c: u8, d: i32, e: u8, f: f32 } extern { fn print_struct(s:TestStruct) -> (); } fn main() { let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; println!("sizeof on Rust side = {} bytes", mem::size_of::<TestStruct>()); unsafe { print_struct(s); } }
8. Překlad a spuštění druhého příkladu
Překlad se provede naprosto stejným způsobem jako v předchozím příkladu:
$ cargo build Compiling gcc v0.3.50 Compiling ffi_project4 v0.1.0 (file:///home/tester/ffi_project4) Finished debug [unoptimized + debuginfo] target(s) in 3.45 secs
Po spuštění však dostaneme odlišný výsledek, protože je hlášeno, že struktura má nyní velikost 24 bajtů a nikoli šestnáct bajtů, i když prvky zůstaly zachovány, pouze se prohodily:
$ cargo run Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/ffi_project4` sizeof on Rust side = 24 bytes sizeof(test_struct) = 24 bytes a = 1 b = 1000 c = 255 d = 10000 e = 127 f = 3.140000
Ve skutečnosti totiž nyní naše datová struktura vypadá následovně:
a: u8, 1 bajt xxx 3 bajty - výplň (padding) b: i32, 4 bajty c: u8, 1 bajt xxx 3 bajty - výplň (padding) d: i32, 4 bajty e: u8, 1 bajt xxx 3 bajty - výplň (padding) f: f32 4 bajty celkem: 24 bajtů
Povšimněte si, že prvky o šířce čtyř bajtů skutečně budou začínat na adrese dělitelné čtyřmi (předpokládáme, že i celá struktura začíná na adrese dělitelné čtyřmi, což je pravda).
9. Export binární podoby struktury
Nepatrnou změnou céčkové části projektu si můžeme ověřit, jakým způsobem je struktura uložena v paměti. Kromě funkce print_struct() použijeme novou funkci export_struct() určenou pro export binárního obrazu struktury do souboru (pro jednoduchost bez testů, zda se soubor podařilo vytvořit, otevřít, zapsat data a zavřít:
void export_struct(test_struct s) { FILE *fout = fopen("test.bin", "wb"); fwrite(&s, sizeof(s), 1, fout); fclose(fout); }
Nová varianta céčkové části bude vypadat následovně:
#include <stdint.h> #include <stdio.h> typedef struct { uint8_t a; int32_t b; uint8_t c; int32_t d; uint8_t e; float f; } test_struct; void export_struct(test_struct s) { FILE *fout = fopen("test.bin", "wb"); fwrite(&s, sizeof(s), 1, fout); fclose(fout); } void print_struct(test_struct s) { printf("sizeof(test_struct) = %lu bytes\n", sizeof(s)); printf("a = %d\n", s.a); printf("b = %d\n", s.b); printf("c = %d\n", s.c); printf("d = %d\n", s.d); printf("e = %d\n", s.e); printf("f = %f\n", s.f); }
Pokud volání nové funkce přidáme do části psané v Rustu, získáme po spuštění projektu soubor pojmenovaný test.bin, který bude mít na architektuře x86–64 délku 24 bajtů a následující obsah:
$ hexdump -C test.bin 00000000 01 a4 8f 30 e8 03 00 00 ff 94 5f 53 10 27 00 00 |...0......_S.'..| 00000010 7f d0 61 2f c3 f5 48 40 |..a/..H@| 00000018
Poznámka: na jiných architekturách může být obsah odlišný, protože se mohou použít odlišná pravidla pro zarovnávání a taktéž může být rozdílný způsob uložení bajtů v širších slovech (little endian versus big endian).
Význam jednotlivých bajtů v souboru je následující:
Offset | Sekvence bajtů | Význam |
---|---|---|
0 | 01 | 0×01 = 1, první celočíselná konstanta typu bajt |
1 | a4 8f 30 | výplň (padding) |
4 | e8 03 00 00 | 0×000003e8 = 1000, druhá celočíselná konstanta typu int32 |
8 | ff | 0×ff = 255, třetí celočíselná konstanta typu bajt |
9 | 94 5f 53 | výplň (padding) |
12 | 10 27 00 00 | 0×00002710 = 10000, čtvrtá celočíselná konstanta typu int32 |
16 | 7f | 0×7f = 127, pátá celočíselná konstanta typu bajt |
17 | d0 61 2f | výplň (padding) |
20 | c3 f5 48 40 | 0×4048f5c3 = π v IEEE 754 reprezentaci |
Porovnejte si tuto tabulku s rozborem struktury provedené v předchozí kapitole.
10. Předání struktury odkazem (přes ukazatel)
Předávání struktur hodnotou (by value), tedy způsobem, který jsme si ukázali v předchozích kapitolách, se sice používá, ale nemusí být vždy ideální. Nejedná se totiž o příliš efektivní operaci, protože – jak jsme sami viděli – je nutné do nativní funkce překopírovat celou strukturu, která je relativně velká (a v reálných příkladech může být ještě větší). Navíc není možné prvky struktury předané hodnotou měnit, což však na druhou stranu může být vítaná vlastnost. Ovšem při komunikaci mezi Rustem a céčkem lze předat i pouhé ukazatele na strukturu, která tak bude mezi oběma částmi aplikace sdílená. V navazujících kapitolách si ukážeme, jak se to provádí.
11. Céčková část aplikace
Nejprve si ukažme, jak se změní céčková část aplikace ve chvíli, kdy jí potřebujeme předat ukazatel na strukturu. Hlavička funkce bude nyní následující (čteme – „s je ukazatel na hodnotu typu test_struct“):
void print_struct(test_struct *s);
Přístup k prvkům struktury přes ukazatel je v céčku velmi snadný, protože lze použít operátor → a zápis s->prvek je mnohem čitelnější než (*s).prvek (zde je navíc nutné použít závorky kvůli prioritě operátorů):
printf("a = %d\n", s->a); printf("b = %d\n", s->b); printf("c = %d\n", s->c); printf("d = %d\n", s->d); printf("e = %d\n", s->e); printf("f = %f\n", s->f);
V upraveném příkladu si navíc necháváme vytisknout jak velikost struktury, tak i velikost ukazatele předaného do volané funkce:
printf("sizeof(pointer) = %lu bytes\n", sizeof(s)); printf("sizeof(test_struct) = %lu bytes\n", sizeof(*s));
Úplný zdrojový kód céčkové části vypadá takto:
#include <stdint.h> #include <stdio.h> typedef struct { uint8_t a; int32_t b; uint8_t c; int32_t d; uint8_t e; float f; } test_struct; void print_struct(test_struct *s) { printf("sizeof(pointer) = %lu bytes\n", sizeof(s)); printf("sizeof(test_struct) = %lu bytes\n", sizeof(*s)); printf("a = %d\n", s->a); printf("b = %d\n", s->b); printf("c = %d\n", s->c); printf("d = %d\n", s->d); printf("e = %d\n", s->e); printf("f = %f\n", s->f); }
12. Část aplikace naprogramovaná v Rustu
I v té části aplikace, která je psaná v Rustu, musí dojít k úpravě, protože potřebujeme získat ukazatel na strukturu. To se provede až překvapivě jednoduše, konkrétně pomocí operátoru &, který slouží k získání reference:
let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; unsafe { let pointer = &s; print_struct(pointer); }
Taktéž je nutné upravit hlavičku externí funkce, protože této funkci předáváme referenci (adresu):
extern { fn print_struct(s: *const TestStruct) -> (); }
Upravený program bude vypadat takto:
use std::mem; #[repr(C)] struct TestStruct { a: u8, b: i32, c: u8, d: i32, e: u8, f: f32 } extern { fn print_struct(s: *const TestStruct) -> (); } fn main() { let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; println!("sizeof on Rust side = {} bytes", mem::size_of::<TestStruct>()); unsafe { let pointer = &s; print_struct(pointer); } }
Spuštění příkladu:
$ cargo run Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/ffi_project5` sizeof on Rust side = 24 bytes sizeof(pointer) = 8 bytes sizeof(test_struct) = 24 bytes a = 1 b = 1000 c = 255 d = 10000 e = 127 f = 3.140000
13. Ukazatel versus reference
Ve skutečnosti zápisem:
let pointer = &s;
získáme referenci a nikoli skutečný ukazatel. Ten lze získat spíše následovně:
let pointer :*const TestStruct = &s;
Samotná hodnota je sice stejná (= adresa struktury), ale způsob práce se liší. U ukazatelů se například nekontroluje, zda ukazují na živou hodnotu, takže lze zapsat:
#[repr(C)] #[derive(Debug)] struct TestStruct { a: u8, b: i32, c: u8, d: i32, e: u8, f: f32 } fn main() { let pointer :*const TestStruct; { let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; pointer = &s; println!("{:?}", pointer); } println!("{:?}", pointer); }
U referencí naproti tomu získáme všechny kontroly překladače:
#[derive(Debug)] struct TestStruct { a: u8, b: i32, c: u8, d: i32, e: u8, f: f32 } fn main() { let pointer; { let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; pointer = &s; println!("{:?}", pointer); } println!("{:?}", pointer); }
Tento program se již nepřeloží (což je ostatně zcela korektní):
error: `s` does not live long enough --> test.rs:16:20 | 16 | pointer = &s; | ^ | note: reference must be valid for the block suffix following statement 0 at 13:16... --> test.rs:13:17 | 13 | let pointer; | ^ note: ...but borrowed value is only valid for the block suffix following statement 0 at 15:84 --> test.rs:15:85 | 15 | let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; | ^ error: aborting due to previous error
14. Modifikace prvků struktury v nativním kódu
Připomeňme si, že céčková část se strukturou předanou přes ukazatel provádět prakticky cokoli, například měnit její prvky:
#include <stdint.h> #include <stdio.h> typedef struct { uint8_t a; int32_t b; uint8_t c; int32_t d; uint8_t e; float f; } test_struct; void print_struct(test_struct *s) { printf("sizeof(pointer) = %lu bytes\n", sizeof(s)); printf("sizeof(test_struct) = %lu bytes\n", sizeof(*s)); printf("a = %d\n", s->a); printf("b = %d\n", s->b); printf("c = %d\n", s->c); printf("d = %d\n", s->d); printf("e = %d\n", s->e); printf("f = %f\n", s->f); } void change_struct(test_struct *s) { s->a = 10; s->b = 20; s->c = 30; s->d = 40; s->e = 50; s->f = 60.0; }
15. Rustovská část
To je ovšem v rozporu s Rustovskou deklarací, kde chybí modifikátor mut:
#[derive(Debug)] #[repr(C)] struct TestStruct { a: u8, b: i32, c: u8, d: i32, e: u8, f: f32 } extern { fn print_struct(s: *const TestStruct) -> (); fn change_struct(s: *const TestStruct) -> (); } fn main() { let s : TestStruct = TestStruct{a:1, b:1000, c:255, d:10000, e:127, f:3.14}; println!("original value: {:?}", s); unsafe { let pointer = &s; print_struct(pointer); change_struct(pointer); print_struct(pointer); } println!("changed value: {:?}", s); }
Na tento rozpor nás ovšem překladač neupozorní (ani překladač Rustu a samozřejmě ani překladač céčka). Podívejme se, co se stane po spuštění aplikace:
$ cargo run Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs Running `target/debug/ffi_project6` original value: TestStruct { a: 1, b: 1000, c: 255, d: 10000, e: 127, f: 3.14 } sizeof(pointer) = 8 bytes sizeof(test_struct) = 24 bytes a = 1 b = 1000 c = 255 d = 10000 e = 127 f = 3.140000 sizeof(pointer) = 8 bytes sizeof(test_struct) = 24 bytes a = 10 b = 20 c = 30 d = 40 e = 50 f = 60.000000 changed value: TestStruct { a: 10, b: 20, c: 30, d: 40, e: 50, f: 60 }
Vidíme, že céčková funkce change_struct() skutečně změnila data Rustu „pod rukama“, což obecně není korektní chování.
16. Repositář s demonstračními příklady
Všechny dnes popisované demonstrační příklady (projekty) byly, ostatně podobně jako ve všech předchozích částech tohoto seriálu, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/presentations. Demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář (ovšem u projektů je lepší mít celý repositář, abyste nemuseli pracně stahovat všechny potřebné soubory):
17. Odkazy na Internetu
- Build Script Support
http://doc.crates.io/build-script.html - Creating a shared and static library with the gnu compiler [gcc]
http://www.adp-gmbh.ch/cpp/gcc/create_lib.html - FFI: Foreign Function Interface
https://doc.rust-lang.org/book/ffi.html - Primitive Type pointer
https://doc.rust-lang.org/std/primitive.pointer.html - Cargo: správce projektů a balíčků pro programovací jazyk Rust
https://mojefedora.cz/cargo-spravce-projektu-a-balicku-pro-programovaci-jazyk-rust/ - Network Communication and Serialization in Rust
https://www.safaribooksonline.com/blog/2014/01/28/network-communication-serialization-rust/ - Crate bincode
http://tyoverby.com/bincode/bincode/index.html - Struct std::fs::File
https://doc.rust-lang.org/std/fs/struct.File.html - Trait std::io::Seek
https://doc.rust-lang.org/std/io/trait.Seek.html - Trait std::io::Read
https://doc.rust-lang.org/std/io/trait.Read.html - Trait std::io::Write
https://doc.rust-lang.org/std/io/trait.Write.html - Trait std::io::BufRead
https://doc.rust-lang.org/std/io/trait.BufRead.html - Module std::io::prelude
https://doc.rust-lang.org/std/io/prelude/index.html - std::net::IpAddr
https://doc.rust-lang.org/std/net/enum.IpAddr.html - std::net::Ipv4Addr
https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html - std::net::Ipv6Addr
https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html - TcpListener
https://doc.rust-lang.org/std/net/struct.TcpListener.html - TcpStream
https://doc.rust-lang.org/std/net/struct.TcpStream.html - Binary heap (Wikipedia)
https://en.wikipedia.org/wiki/Binary_heap - Binární halda (Wikipedia)
https://cs.wikipedia.org/wiki/Bin%C3%A1rn%C3%AD_halda - Halda (datová struktura)
https://cs.wikipedia.org/wiki/Halda_%28datov%C3%A1_struktura%29 - Struct std::collections::HashSet
https://doc.rust-lang.org/std/collections/struct.HashSet.html - Struct std::collections::BTreeSet
https://doc.rust-lang.org/std/collections/struct.BTreeSet.html - Struct std::collections::BinaryHeap
https://doc.rust-lang.org/std/collections/struct.BinaryHeap.html - Set (abstract data type)
https://en.wikipedia.org/wiki/Set_%28abstract_data_type%29#Language_support - Associative array
https://en.wikipedia.org/wiki/Associative_array - Hash Table
https://en.wikipedia.org/wiki/Hash_table - B-tree
https://en.wikipedia.org/wiki/B-tree - Pedro Celis: Robin Hood Hashing (naskenované PDF!)
https://cs.uwaterloo.ca/research/tr/1986/CS-86–14.pdf - Robin Hood hashing
http://codecapsule.com/2013/11/11/robin-hood-hashing/ - Robin Hood hashing: backward shift deletion
http://codecapsule.com/2013/11/17/robin-hood-hashing-backward-shift-deletion/ - Module std::collections
https://doc.rust-lang.org/std/collections/ - Module std::vec
https://doc.rust-lang.org/nightly/std/vec/index.html - Struct std::collections::VecDeque
https://doc.rust-lang.org/std/collections/struct.VecDeque.html - Struct std::collections::LinkedList
https://doc.rust-lang.org/std/collections/struct.LinkedList.html - Module std::fmt
https://doc.rust-lang.org/std/fmt/ - Macro std::println
https://doc.rust-lang.org/std/macro.println.html - Enum std::result::Result
https://doc.rust-lang.org/std/result/enum.Result.html - Module std::result
https://doc.rust-lang.org/std/result/ - Result
http://rustbyexample.com/std/result.html - Rust stdlib: Option
https://doc.rust-lang.org/std/option/enum.Option.html - Module std::option
https://doc.rust-lang.org/std/option/index.html - Rust by example: option
http://rustbyexample.com/std/option.html - Rust by example: if-let
http://rustbyexample.com/flow_control/if_let.html - Rust by example: while let
http://rustbyexample.com/flow_control/while_let.html - Rust by example: Option<i32>
http://rustbyexample.com/std/option.html - An Overview of Macros in Rust
http://words.steveklabnik.com/an-overview-of-macros-in-rust - A Practical Intro to Macros in Rust 1.0
https://danielkeep.github.io/practical-intro-to-macros.html - The Rust Programming Language: macros
https://doc.rust-lang.org/beta/book/macros.html - Rust by example: 15 macro_rules!
http://rustbyexample.com/macros.html - Primitive Type isize
https://doc.rust-lang.org/nightly/std/primitive.isize.html - Primitive Type usize
https://doc.rust-lang.org/nightly/std/primitive.usize.html - Primitive Type array
https://doc.rust-lang.org/nightly/std/primitive.array.html - Module std::slice
https://doc.rust-lang.org/nightly/std/slice/ - Rust by Example: 2.3 Arrays and Slices
http://rustbyexample.com/primitives/array.html - What is the difference between Slice and Array (stackoverflow)
http://stackoverflow.com/questions/30794235/what-is-the-difference-between-slice-and-array - Learning Rust With Entirely Too Many Linked Lists
http://cglab.ca/~abeinges/blah/too-many-lists/book/ - Testcase: linked list
http://rustbyexample.com/custom_types/enum/testcase_linked_list.html - Operators and Overloading
https://doc.rust-lang.org/book/operators-and-overloading.html - Module std::ops
https://doc.rust-lang.org/std/ops/index.html - Module std::cmp
https://doc.rust-lang.org/std/cmp/index.html - Trait std::ops::Add
https://doc.rust-lang.org/stable/std/ops/trait.Add.html - Trait std::ops::AddAssign
https://doc.rust-lang.org/std/ops/trait.AddAssign.html - Trait std::ops::Drop
https://doc.rust-lang.org/std/ops/trait.Drop.html - Trait std::cmp::Eq
https://doc.rust-lang.org/std/cmp/trait.Eq.html - Struct std::boxed::Box
https://doc.rust-lang.org/std/boxed/struct.Box.html - Explore the ownership system in Rust
https://nercury.github.io/rust/guide/2015/01/19/ownership.html - Rust's ownership and move semantic
http://www.slideshare.net/saneyuki/rusts-ownership-and-move-semantics - Trait std::marker::Copy
https://doc.rust-lang.org/stable/std/marker/trait.Copy.html - Trait std::clone::Clone
https://doc.rust-lang.org/stable/std/clone/trait.Clone.html - The Stack and the Heap
https://doc.rust-lang.org/book/the-stack-and-the-heap.html - Rust Compare: Pointers & References
http://www.rust-compare.com/site/pointers.html - Rust Compare: Parameters
http://www.rust-compare.com/site/params.html - Why does this compile? Automatic dereferencing?
https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183 - Understanding Pointers, Ownership, and Lifetimes in Rust
http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html - Rust lang series episode #25 — pointers (#rust-series)
https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series - Rust – home page
https://www.rust-lang.org/en-US/ - Rust – Frequently Asked Questions
https://www.rust-lang.org/en-US/faq.html - Destructuring and Pattern Matching
https://pzol.github.io/getting_rusty/posts/20140417_destructuring_in_rust/ - The Rust Programming Language
https://doc.rust-lang.org/book/ - Rust (programming language)
https://en.wikipedia.org/wiki/Rust_%28programming_language%29 - Go – home page
https://golang.org/ - Stack Overflow – Most Loved, Dreaded, and Wanted language
https://stackoverflow.com/research/developer-survey-2016#technology-most-loved-dreaded-and-wanted - Rust vs Go (dva roky staré hodnocení, od té doby došlo k posunům v obou jazycích)
http://jaredforsyth.com/2014/03/22/rust-vs-go/ - Rust vs Go: My experience
https://www.reddit.com/r/golang/comments/21m6jq/rust_vs_go_my_experience/ - Friends of Rust (Organizations running Rust in production)
https://www.rust-lang.org/en-US/friends.html - Rust programs versus C++ g++
https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=rust&lang2=gpp - Další benchmarky (nejedná se o reálné příklady „ze života“)
https://github.com/kostya/benchmarks - Go na Redditu
https://www.reddit.com/r/golang/ - Rust vs. Go
http://vschart.com/compare/rust/vs/go-language - Abstraction without overhead: traits in Rust
https://blog.rust-lang.org/2015/05/11/traits.html - Method Syntax
https://doc.rust-lang.org/book/method-syntax.html - Traits in Rust
https://doc.rust-lang.org/book/traits.html - Functional Programming in Rust – Part 1 : Function Abstraction
http://blog.madhukaraphatak.com/functional-programming-in-rust-part-1/ - Of the emerging systems languages Rust, D, Go and Nim, which is the strongest language and why?
https://www.quora.com/Of-the-emerging-systems-languages-Rust-D-Go-and-Nim-which-is-the-strongest-language-and-why - Chytré ukazatele (moderní verze jazyka C++) [MSDN]
https://msdn.microsoft.com/cs-cz/library/hh279674.aspx - UTF-8 Everywhere
http://utf8everywhere.org/ - Rust by Example
http://rustbyexample.com/ - Rust oficiálně ve Fedoře
https://mojefedora.cz/rust-oficialne-ve-fedore/ - Resource acquisition is initialization
https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization - TIOBE index (October 2016)
http://www.tiobe.com/tiobe-index/ - Porovnání Go, D a Rustu na OpenHubu:
https://www.openhub.net/languages/compare?language_name[]=-1&language_name[]=-1&language_name[]=dmd&language_name[]=golang&language_name[]=rust&language_name[]=-1&measure=commits - String Types in Rust
http://www.suspectsemantics.com/blog/2016/03/27/string-types-in-rust/ - Trait (computer programming)
https://en.wikipedia.org/wiki/Trait_%28computer_programming%29 - Type inference
https://en.wikipedia.org/wiki/Type_inference