Obsah
1. Programovací jazyk Rust: použití FFI pro volání funkcí z nativních knihoven
2. Céčkový zdrojový kód s nativní funkcí
3. Překlad funkce do objektového souboru a vytvoření statické knihovny
4. Použití statické knihovny v Rustu
5. Překlad a spuštění aplikace psané v Rustu, která volá funkci ze statické knihovny
6. Zjednodušení procesu překladu a spouštění: jednoduchý Makefile
7. Překlad funkce do objektového souboru a vytvoření dynamické knihovny
8. Použití dynamické knihovny v Rustu
9. Překlad a spuštění aplikace psané v Rustu, která volá funkci z dynamické knihovny
10. Pomocný soubor Makefile pro druhý příklad
11. Problematika řetězců – C versus Rust
12. Předání řetězce do volané nativní funkce
13. Dangling pointers a jak je nevytvářet
14. Repositář s demonstračními příklady
1. Programovací jazyk Rust: použití FFI pro volání funkcí z nativních knihoven
V Rustu, podobně jako v mnoha dalších programovacích jazycích (Python, Lua, Common Lisp, Pixie…), je možné volat funkce z nativních knihoven (slovem „nativní“ je zde myšlena knihovna vytvořená pro danou architekturu mikroprocesoru). Tyto funkce mohou být naprogramovány například v jazyku C či C++, přeloženy a jejich objektový kód naimportován do statické či dynamické knihovny. Dnes si ukážeme, jak se takové knihovny (statické i dynamické) vytváří a jakým způsobem se nativním funkcím předávají parametry. Zmíníme se i o velmi často řešené problematice – předávání řetězců do nativních funkcí.
2. Céčkový zdrojový kód s nativní funkcí
Pro jednoduchost předpokládejme, že budeme potřebovat zavolat nativní funkci, která sečte dvě celá čísla (se znaménkem) a vrátí vypočtený výsledek. První verze této funkce (naprogramované v céčku) může vypadat následovně:
int add(int x, int y) { return x+y; }
Takovou funkci je samozřejmě možné přeložit a použít, ovšem při volání funkce add z Rustu se můžeme poměrně rychle dostat do problémů ve chvíli, kdy šířka datového typu int nebude přesně odpovídat datovému typu použitému na straně Rustu (připomeňme si, že Rust je portován na 32bitové i 64bitové CPU a navíc jeho variantu nalezneme i na šestnáctibitových mikrořadičích MSP430). Navíc ani nedochází ke kontrole, zda jsou šířky datových typů použity korektně. Proto je bezpečnější uvádět datové typy parametrů funkce i její návratové hodnoty zcela explicitně, například takto:
#include <stdint.h> int32_t add(int32_t x, int32_t y) { return x+y; }
Převodní tabulka mezi celočíselnými typy v C a typy Rustu:
Typ v C | Typ v Rustu | Význam |
---|---|---|
int8_t | i8 | celé číslo se znaménkem (signed) o šířce 8 bitů |
int16_t | i16 | celé číslo se znaménkem (signed) o šířce 16 bitů |
int32_t | i32 | celé číslo se znaménkem (signed) o šířce 32 bitů |
int64_t | i64 | celé číslo se znaménkem (signed) o šířce 64 bitů |
uint8_t | u8 | celé číslo bez znaménka (unsigned) o šířce 8 bitů |
uint16_t | u16 | celé číslo bez znaménka (unsigned) o šířce 16 bitů |
uint32_t | u32 | celé číslo bez znaménka (unsigned) o šířce 32 bitů |
uint64_t | u64 | celé číslo bez znaménka (unsigned) o šířce 64 bitů |
3. Překlad funkce do objektového souboru a vytvoření statické knihovny
V prvním kroku céčkovský zdrojový kód přeložíme překladačem gcc (lze však použít i clang), a to následujícím způsobem:
gcc -Wall -ansi -c ffi1.c -o ffi1.o
Poznámka: na rozdíl od druhého příkladu nemusíme při kompilaci uvádět přepínač -fPIC zajištující vygenerování pozičně nezávislého strojového kódu (Position-Independent Code).
V kroku druhém dojde k vytvoření statické knihovny. Pro tento účel použijeme nástroj ar s přepínači „r“ (přidání souboru do archivu představujícího statickou knihovnu), „c“ (vytvoření archivu/knihovny) a „s“ (vytvoření indexu). Přepínače se z historických důvodů mohou uvádět bez znaku pomlčky:
ar rcs libffi1.a ffi1.o
Pokud chcete zjistit, jaké symboly (popř. i kód) se v knihovně nachází, použijte nástroj nm:
nm -s libffi1.a Archive index: add in ffi1.o ffi1.o: 0000000000000000 T add
4. Použití statické knihovny v Rustu
Pokud budeme chtít nativní funkci add zavolat z Rustu, je nutné specifikovat, ve které knihovně je uložen strojový kód funkce a zda se jedná o knihovnu statickou či dynamickou. Dále je nutné v bloku extern {} uvést hlavičku funkce s použitím typů Rustu. Pro funkci se dvěma celočíselnými 32bitovými parametry se znaménkem, která vrací stejný typ (32bitové celé číslo se znaménkem) a která je uložena ve statické knihovně libffi1.a je deklarace následující:
#[link(name = "ffi1", kind="static")] extern { fn add(x:i32, y:i32) -> i32; }
Ze jména „ffi1“ je odvozen název knihovny, parametr „kind“ specifikuje knihovnu statickou (u dynamické knihovny se neuvádí).
Zavolání nativní funkce je snadné:
let x:i32 = 1; let y:i32 = 2; let z = add(x, y);
Ve skutečnosti však není volání nativní funkce bezpečné, což nám řekne překladač:
--> ffi1.rs:9:13 | 9 | let z = add(x, y); | ^^^^^^^^^ unsafe call requires unsafe function or block error: aborting due to previous error
Z tohoto důvodu je nutné volání funkce umístit do bloku unsafe {}:
let x:i32 = 1; let y:i32 = 2; let z = unsafe { add(x, y) };
Celý příklad (resp. jeho rustovská část) bude vypadat následovně:
#[link(name = "ffi1", kind="static")] extern { fn add(x:i32, y:i32) -> i32; } fn main() { let x:i32 = 1; let y:i32 = 2; let z = unsafe { add(x, y) }; println!("{} + {} = {}", x, y, z); }
5. Překlad a spuštění aplikace psané v Rustu, která volá funkci ze statické knihovny
Při překladu zdrojového kódu psaného v Rustu se volá i linker, který musí vědět, kde je umístěna statická knihovna libffi1.a. Cestu ke knihovně/knihovnám můžeme předat přes parametr L, který bude obsahovat aktuální adresář (tedy tečku):
rustc -L . ffi1.rs
Díky tomu, že se program linkuje se statickou knihovnou (resp. jejím obsahem), není nutné soubor libffi1.a distribuovat současně s aplikací (používá se jen při vývoji).
Spuštění příkladu je již jednoduché:
$ ./ffi1 1 + 2 = 3
6. Zjednodušení procesu překladu a spouštění: jednoduchý Makefile
Aby nebylo nutné výše uvedené kroky provádět neustále dokola po každé úpravě části psané v jazyku C či naopak v Rusu, můžeme si vytvořit jednoduchý soubor Makefile, který překlad a slinkování automatizuje:
CC=gcc CFLAGS=-Wall -ansi RUSTC=rustc APP=ffi1 PROGNAME=$(APP) LIBNAME=lib$(APP).a RUST_SRC=$(APP).rs LIB_SRC=$(APP).c OBJ_FILE=$(APP).o # Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace. all: $(LIBNAME) $(PROGNAME) # Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni # vysledne spustitelne aplikace. $(PROGNAME): $(RUST_SRC) $(LIBNAME) $(RUSTC) -L . $< # Pravidlo pro preklad knihovny $(LIBNAME): $(OBJ_FILE) ar rcs $(LIBNAME) $< %.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@ clean: rm -f *.o rm -f *.a rm -f $(PROGNAME) run: ./$(APP)
7. Překlad funkce do objektového souboru a vytvoření dynamické knihovny
Mnohem častěji se setkáme s nutností volat nativní funkce uložené v dynamických knihovnách. Můžeme se tedy pokusit si vytvořit dynamickou knihovnu s naší funkcí add. Není to nic těžkého, ovšem je nutné dodržet několik pravidel, například překládat do pozičně nezávislého strojového kódu atd.
Postupovat je možné následujícím způsobem. Nejdříve se musí provést překlad céčkového zdrojového kódu do nativního objektového kódu, což se zdánlivě nijak neliší od předchozího příkladu, ovšem musíme zde nově použít přepínač -fPIC:
gcc -Wall -ansi -c -fPIC ffi2.c -o ffi2.o
Výsledkem je objektový soubor nazvaný ffi2.o. Následně se vytvoří dynamická knihovna příkazem:
gcc -shared -Wl,-soname,libffi2.so -o libffi2.so ffi2.o
Povšimněte si, že výsledná knihovna má prefix „lib“. To je důležité, neboť kdyby tento prefix nebyl použit a knihovna se jmenovala jen ffi2.so, nastaly by problémy s jejím načítáním (ty jsou samozřejmě řešitelné, ale proč si zbytečně přidělávat práci nestandardním pojmenováním?)
8. Použití dynamické knihovny v Rustu
Pokud se volá funkce z dynamické knihovny, je nutné program nepatrně upravit. Týká se to vlastně jen řádku:
#[link(name = "ffi1", kind="static")]
u nějž se vynechá specifikace kind a její hodnota. Je tomu tak z toho důvodu, že výchozím typem knihovny je knihovna dynamická:
#[link(name = "ffi2")]
Upravený program tedy bude vypadat následovně:
#[link(name = "ffi2")] extern { fn add(x:i32, y:i32) -> i32; } fn main() { let x:i32 = 1; let y:i32 = 2; let z = unsafe { add(x, y) }; println!("{} + {} = {}", x, y, z); }
I v tomto případě je nutné blok unsafe uvést, protože následující upravený příklad se nepřeloží:
#[link(name = "ffi2")] extern { fn add(x:i32, y:i32) -> i32; } fn main() { let x:i32 = 1; let y:i32 = 2; let z = add(x, y); println!("{} + {} = {}", x, y, z); }
Chybové hlášení překladače:
error[E0133]: call to unsafe function requires unsafe function or block --> ffi2.rs:9:14 | 9 | let z = add(x, y); | ^^^^^^^^^ unsafe call requires unsafe function or block error: aborting due to previous error
9. Překlad a spuštění aplikace psané v Rustu, která volá funkci z dynamické knihovny
Překlad se provede nám již známým způsobem, tj. uvedením cesty k nativní linkované knihovně:
rustc -L . ffi2.rs
Spuštění ovšem bude komplikovanější, neboť se při snaze o prosté spuštění aplikace vypíše toto chybové hlášení oznamující, že v runtime nebylo možné nalézt požadovanou dynamickou knihovnu:
./ffi2: error while loading shared libraries: libffi2.so: cannot open shared object file: No such file or directory
Vzhledem k tomu, že námi vytvořená knihovna skutečně není umístěna do adresářů, v níž se sdílené knihovny hledají, musíme nastavit proměnnou prostředí LD_LIBRARY_PATH. Buď pro aktivní shell:
export LD_LIBRARY_PATH=. ./ffi2
nebo pouze pro jeden příkaz:
LD_LIBRARY_PATH=. ./ffi2
Pokud potřebujete zjistit, ve kterých adresářích se sdílené knihovny hledají, stačí použít příkaz (může si lišit podle typu distribuce):
cat /etc/ld.so.conf.d/* /usr/lib/x86_64-linux-gnu/libfakeroot /usr/lib/i386-linux-gnu/mesa # Multiarch support /lib/i386-linux-gnu /usr/lib/i386-linux-gnu /lib/i686-linux-gnu /usr/lib/i686-linux-gnu # libc default configuration /usr/local/lib /usr/local/lib # Multiarch support /lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu /usr/lib/x86_64-linux-gnu/mesa-egl /usr/lib/x86_64-linux-gnu/mesa
10. Pomocný soubor Makefile pro druhý příklad
CC=gcc CFLAGS=-Wall -ansi -fPIC RUSTC=rustc APP=ffi2 PROGNAME=$(APP) LIBNAME=lib$(APP).so RUST_SRC=$(APP).rs LIB_SRC=$(APP).c OBJ_FILE=$(APP).o # Vychozi pravidlo pro vytvoreni vysledne spustitelne aplikace. all: $(LIBNAME) $(PROGNAME) # Pravidlo pro slinkovani vsech objektovych souboru a vytvoreni # vysledne spustitelne aplikace. $(PROGNAME): $(RUST_SRC) $(LIBNAME) $(RUSTC) -L . $< # Pravidlo pro preklad knihovny $(LIBNAME): $(OBJ_FILE) $(CC) -shared -Wl,-soname,$(LIBNAME) -o $(LIBNAME) $< %.o: %.c $(CC) $(CFLAGS) $(INCLUDES) -c $< clean: rm -f *.o rm -f *.so rm -f $(PROGNAME) run: export LD_LIBRARY_PATH=.;./$(APP)
11. Problematika řetězců – C versus Rust
V programovacím jazyku Rust existuje hned několik datových typů určených pro úschovu řetězců. Obecně se tyto typy rozdělují do dvou skupin podle toho, zda se jedná o takzvanou „slice“ variantu (sem spadají řetězce umístěné v kódovém segmentu) a o řetězce obalené vhodným kontejnerem a typicky umístěné na haldě. V každé skupině nalezneme čtyři typy: řetězce s kódováním UTF-8, řetězce kompatibilní s céčkem (nutno použít při volání céčkových knihoven), řetězce kompatibilní s operačním systémem (může se jednat o typ shodný s předchozím) a konečně řetězce, které mohou uchovávat cestu k souborům a adresářům (opět – nemusí se nutně jednat o zcela odlišný datový typ):
Vlastnost | Varianta „slice“ | Varianta „Owned“ |
---|---|---|
UTF-8 string | str | String |
Kompatibilní s C | CStr | CString |
Kompatibilní s OS | OsStr | OsString |
Cesta (v OS) | Path | PathBuf |
Nás budou v tuto chvíli zajímat především řetězce kompatibilní s céčkem. Tyto řetězce interně vypadají odlišně od řetězců v Rustu, protože v céčku se namísto reference na pole znaků zkombinované s délkou pole používají řetězce ukončené nulou. Zkusme si vytvořit nativní funkci, která vrátí počet bajtů (ne nutně znaků!) v řetězci. Jedna z možných implementací může vypadat následovně:
#include <stdint.h> int32_t string_length(const char *str) { int32_t len = 0; for (; *str; str++, len++) ; return len; }
Ve funkci postupně zvyšujeme ukazatel a testujeme, zda jsme nedosáhli konce řetězce, tedy bajtu s hodnotou nula. Současně zvyšujeme i počitadlo, jehož hodnota po ukončení smyčky obsahuje počet bajtů v řetězci.
Taková funkce se v Rustu popíše následovně (povšimněte si typu *const c_char):
#[link(name = "ffi3")] extern { fn string_length(str: *const c_char) -> i32; }
12. Předání řetězce do volané nativní funkce
Předání rustovského řetězce do céčka nelze provést přímo, ale je nejdříve nutné řetězec převést do kompatibilního objektu, tedy do struktury CString či CStr. K tomu slouží konstruktor CString:new() vracející typ Result<CString, NulError>:
CString::new("Hello world!").unwrap();
nebo lépe:
match CString::new("Hello world!") { Ok(string) => { ... ... ... } Err(error) => { println!("CString::new() error: {:?}", error); } }
Následně se získá ukazatel na první znak v řetězci:
let pointer = string.as_ptr();
Teprve tento ukazatel se předá nativní funkci:
unsafe { println!("string length = {}", string_length(pointer)); }
Úplný zdrojový kód může vypadat následovně:
use std::ffi::CString; use std::os::raw::c_char; #[link(name = "ffi3")] extern { fn string_length(str: *const c_char) -> i32; } fn main() { match CString::new("Hello world!") { Ok(string) => { let pointer = string.as_ptr(); unsafe { println!("string length = {}", string_length(pointer)); } } Err(error) => { println!("CString::new() error: {:?}", error); } } }
Po překladu a spuštění se vypíše:
string length = 12
13. Dangling pointers a jak je nevytvářet
Dejte si pozor na to, že sice můžeme napsat:
let pointer = CString::new("Hello world!").unwrap().as_ptr(); unsafe { println!("string length = {}", string_length(pointer)); }
ale ve skutečnosti se nebude jednat o korektní program, protože platnost řetězce skončí ihned po provedení prvního výrazu a samotný ukazatel nenese – jak již víme z předchozích dvou dílů – žádnou informaci o životnosti hodnoty, na níž ukazuje! To znamená, že řetězec je po ukončení prvního výrazu odstraněn (resp. minimálně zneplatněn), ovšem o dva řádky dále používáme ukazatel na nyní již neplatná data!
Korektní způsob spočívá v rozdělení prvního řádku na dva:
let string = CString::new("Hello world!").unwrap(); let pointer = string.as_ptr(); unsafe { println!("string length = {}", string_length(pointer)); }
Nyní je již proměnná string platná v celém bloku.
14. Repositář s demonstračními příklady
Všechny dnes popisované demonstrační příklady a podpůrné skripty 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ář:
Poznámka: poslední zmíněný příklad ffi4 si popíšeme příště.
15. Odkazy na Internetu
- GNU C Library: Integers
https://www.gnu.org/software/libc/manual/html_node/Integers.html - Position-independent code
https://cs.wikipedia.org/wiki/Position-independent_code - 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