All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the authors, nor Packt Publishing or its dealers and distributors, will be held liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
First published: May 2019
Production reference: 1200519
Published by Packt Publishing Ltd. Livery Place
35 Livery Street Birmingham B3 2PB, UK.
ISBN 978-1-83882-810-3
www.packtpub.com
Mapt is an online digital library that gives you full access to over 5,000 books and videos, as well as industry leading tools to help you plan your personal development and advance your career. For more information, please visit our website.
Why subscribe?
Spend less time learning and more time coding with practical eBooks and Videos from over 4,000 industry professionals
Improve your learning with Skill Plans built especially for you
Get a free eBook or video every month
Mapt is fully searchable
Copy and paste, print, and bookmark content
Packt.com
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.packt.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at customercare@packtpub.com for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of free newsletters, and receive exclusive discounts and offers on Packt books and eBooks.
Contributors
About the authors
Rahul Sharma is passionately curious about teaching programming. He has been writing software for the last two years. He got started with Rust with his work on Servo, a browser engine by Mozilla Research as part of his GSoC project. At present, he works at AtherEnergy, where he is building resilient cloud infrastructure for smart scooters. His interests include systems programming, distributed systems, compilers and type theory. He is also an occasional contributor to the Rust language and does mentoring of interns on the Servo project by Mozilla.
Vesa Kaihlavirta has been programming since he was five, beginning with C64 Basic. His main professional goal in life is to increase awareness of programming languages and software quality in all industries that use software. He's an Arch Linux Developer Fellow, and has been working in the telecom and financial industry for a decade. Vesa lives in Jyvaskyla, central Finland.
Claus Matzinger is a software engineer with a very diverse background. After working in a small company maintaining code for embedded devices, he joined a large corporation to work on legacy Smalltalk applications. This led to a great interest in programming languages early on, and Claus became the CTO for a health games start-up based on Scala technology. Since then, Claus' roles have shifted toward customer-facing roles in the IoT database technology start-up crate.io and, most recently, Microsoft. There, he hosts a podcast, writes code together with customers, and blogs about the solutions arising from these engagements. For more than 5 years, Claus has implemented software to help customers innovate, achieve, and maintain success.
Packt is searching for authors like you
If you're interested in becoming an author for Packt, please visit autho rs.packtpub.com and apply today. We have worked with thousands of developers and tech professionals, just like you, to help them share their insight with the global tech community. You can make a general application, apply for a specific hot topic that we are recruiting an author for, or submit your own idea.
Table of Contents
Title Page
Copyright
The Complete Rust Programming Reference Guide
About Packt
Why subscribe?
Packt.com
Contributors
About the authors
Packt is searching for authors like you
Preface
Who this book is for
What this book covers
To get the most out of this book
Download the example code files
Conventions used
Get in touch
Reviews
1. Getting Started with Rust
What is Rust and why should you care?
Installing the Rust compiler and toolchain
Using rustup.rs
A tour of the language
Primitive types
Declaring variables and immutability
Functions
Closures
Strings
Conditionals and decision making
Match expressions
Loops
User-defined types
Structs
Enums
Functions and methods on types
Impl blocks on structs
Impl blocks for enums
Modules, imports, and use statements
Collections
Arrays
Tuples
Vectors
Hashmaps
Slices
Iterators
Exercise – fixing the word counter
Summary
2. Managing Projects with Cargo
Package managers
Modules
Nested modules
File as a module
Directory as module
Cargo and crates
Creating a new Cargo project
Cargo and dependencies
Running tests with Cargo
Running examples with Cargo
Cargo workspace
Extending Cargo and tools
Subcommands and Cargo installation
cargo-watch
cargo-edit
cargo-deb
cargo-outdated
Linting code with clippy
Exploring the manifest file – Cargo.toml
Setting up a Rust development environment
Building a project with Cargo – imgtool
Summary
3. Tests, Documentation, and Benchmarks
Motivation for testing
Organizing tests
Testing primitives
Attributes
Assertion macros
Unit tests
First unit test
Running tests
Isolating test code
Failing tests
Ignoring tests
Integration tests
First integration test
Sharing common code
Documentation
Writing documentation
Generating and viewing documentation
Hosting documentation
Doc attributes
Documentation tests
Benchmarks
Built-in micro-benchmark harness
Benchmarking on stable Rust
Writing and testing a crate – logic gate simulator
Continuous integration with Travis CI
Summary
4. Types, Generics, and Traits
Type systems and why they matter
Generics
Creating generic types
Generic functions
Generic types
Generic implementations
Using generics
Abstracting behavior with traits
Traits
The many forms of traits
Marker traits
Simple traits
Generic traits
Associated type traits
Inherited traits
Using traits with generics – trait bounds
Trait bounds on types
Trait bounds on generic functions and impl blocks
Using + to compose traits as bounds
Trait bounds with impl trait syntax
Exploring standard library traits
True polymorphism using trait objects
Dispatch
Trait objects
Summary
5. Memory Management and Safety
Programs and memory
How do programs use memory?
Memory management and its kinds
Approaches to memory allocation
The stack
The heap
Memory management pitfalls
Memory safety
Trifecta of memory safety
Ownership
A brief on scopes
Move and copy semantics
Duplicating types via traits
Copy
Clone Ownership in action
Borrowing
Borrowing rules
Borrowing in action
Method types based on borrowing
Lifetimes
Lifetime parameters
Lifetime elision and the rules
Lifetimes in user defined types
Lifetime in impl blocks
Multiple lifetimes
Lifetime subtyping
Specifying lifetime bounds on generic types
Pointer types in Rust
References – safe pointers
Raw pointers
Smart pointers Drop
Deref and DerefMut
Types of smart pointers
Box<T>
Reference counted smart pointers
Rc<T>
Interior mutability
Cell<T>
RefCell<T>
Uses of interior mutability
Summary
6. Error Handling
Error handling prelude
Recoverable errors
Option
Result
Combinators on Option/Result
Common combinators
Using combinators
Converting between Option and Result
Early returns and the ? operator
Non-recoverable errors
User-friendly panics
Custom errors and the Error trait
Summary
7. Advanced Concepts
Type system tidbits
Blocks and expressions
Let statements
Loop as an expression
Type clarity and sign distinction in numeric types
Type inference
Type aliases
Strings
Owned strings – String
Borrowed strings – &str
Slicing and dicing strings
Using strings in functions
Joining strings
When to use &str versus String ?
Global values
Constants
Statics
Compile time functions – const fn
Dynamic statics using the lazy_static! macro
Iterators
Implementing a custom iterator
Advanced types
Unsized types
Function types
Never type ! and diverging functions
Unions
Cow
Advanced traits
Sized and ?Sized
Borrow and AsRef
ToOwned
From and Into
Trait objects and object safety
Universal function call syntax
Trait rules
Closures in depth
Fn closures
FnMut closures
FnOnce closures
Consts in structs, enums, and traits
Modules, paths, and imports
Imports
Re-exports
Selective privacy
Advanced match patterns and guards
Match guards
Advanced let destructure
Casting and coercion
Types and memory
Memory alignment
Exploring the std::mem module
Serialization and deserialization using serde
Summary
8. Concurrency
Program execution models
Concurrency
Approaches to concurrency
Kernel-based
User-level
Pitfalls
Concurrency in Rust
Thread basics
Customizing threads
Accessing data from threads
Concurrency models with threads
Shared state model
Shared ownership with Arc
Mutating shared data from threads
Mutex
Shared mutability with Arc and Mutex
RwLock
Communicating through message passing
Asynchronous channels
Synchronous channels
thread-safety in Rust
What is thread-safety?
Traits for thread-safety
Send Sync
Concurrency using the actor model
Other crates
Summary
9. Metaprogramming with Macros
What is metaprogramming?
When to use and not use Rust macros
Macros in Rust and their types
Types of macros
Creating your first macro with macro_rules!
Built-in macros in the standard library
macro_rules! token types
Repetitions in macros
A more involved macro – writing a DSL for HashMap initializat ion
Macro use case – writing tests
Exercises
Procedural macros
Derive macros
Debugging macros
Useful procedural macro crates
Summary
10. Unsafe Rust and Foreign Function Interfaces
What is safe and unsafe really?
Unsafe functions and blocks
Unsafe traits and implementations
Calling C code from Rust
Calling Rust code from C
Using external C/C++ libraries from Rust
Creating native Python extensions with PyO3
Creating native extensions in Rust for Node.js
Summary
11. Logging
What is logging and why do we need it?
The need for logging frameworks
Logging frameworks and their key features
Approaches to logging
Unstructured logging
Structured logging
Logging in Rust
log – Rust's logging facade
The env_logger
log4rs
Structured logging using slog
Summary
12. Network Programming in Rust
Network programming prelude
Synchronous network I/O
Building a synchronous redis server
Asynchronous network I/O
Async abstractions in Rust
Mio
Futures
Tokio
Building an asynchronous redis server
Summary
13. Building Web Applications with Rust
Web applications in Rust
Typed HTTP with Hyper
Hyper server APIs – building a URL shortener 
hyper as a client – building a URL shortener client
Web frameworks
Actix-web basics
Building a bookmarks API using Actix-web
Summary
14. Lists, Lists, and More Lists
Linked lists
A transaction log
Adding entries
Log replay
After use
Wrap up
Upsides
Downsides
Doubly linked list
A better transaction log
Examining the log
Reverse
Wrap up
Upsides
Downsides
Skip lists
The best transaction log
The list
Adding data
Leveling up
Jumping around
Thoughts and discussion
Upsides
Downsides
Dynamic arrays
Favorite transactions
Internal arrays
Quick access
Wrap up
Upsides
Downsides
Summary
Further reading
15. Robust Trees
Binary search tree
IoT device management
More devices
Finding the right one
Finding all devices
Wrap up
Upsides
Downsides
Red-black tree
Better IoT device management
Even more devices
Balancing the tree
Finding the right one, now
Wrap up
Upsides
Downsides
Heaps
A huge inbox
Getting messages in
Taking messages out
Wrap up
Upsides
Downsides
Trie
More realistic IoT device management
Adding paths
Walking
Wrap up
Upsides
Downsides
B-Tree An IoT database
Adding stuff
Searching for stuff
Walking the tree
Wrap up
Upsides
Downsides
Graphs
The literal Internet of Things
Neighborhood search
The shortest path
Wrap up
Upsides
Downsides
Summary
16. Exploring Maps and Sets
Hashing
Create your own
Message digestion
Wrap up
Maps
A location cache
The hash function
Adding locations
Fetching locations
Wrap up
Upsides
Downsides
Sets
Storing network addresses
Networked operations
Union Intersection Difference
Wrap up
Upsides
Downsides
Summary
Further reading
17. Collections in Rust
Sequences
Vec<T> and VecDeque<T> Architecture
Insert Look up
Remove
LinkedList<T> Architecture
Insert Look up Remove
Wrap up
Maps and sets
HashMap and HashSet
Architecture Insert Lookup
Remove
BTreeMap and BTreeSet Architecture Insert Look up
Remove
Wrap up
Summary Further reading
18. Algorithm Evaluation
The Big O notation
Other people's code
The Big O Asymptotic runtime complexity
Making your own Loops
Recursion
Complexity classes
O(1)
O(log(n))
O(n)
O(n log(n))
O(n²)
O(2n)
Comparison
In the wild
Data structures
Everyday things
Exotic things
Summary
Further reading
19. Ordering Things
From chaos to order
Bubble sort
Shell sort
Heap sort
Merge sort
Quicksort
Summary
Further reading
20. Finding Stuff
Finding the best
Linear searches
Jump search
Binary searching
Wrap up
Summary
Further reading
21. Random and Combinatorial
Pseudo-random numbers
LCG
Wichmann-Hill
The rand crate
Back to front
Packing bags or the 0-1 knapsack problem
N queens
Advanced problem solving
Dynamic programming
The knapsack problem improved
Metaheuristic approaches
Example metaheuristic – genetic algorithms
Summary
Further reading
22. Algorithms of the Standard Library
Slicing and iteration
Iterator
Slices
Search
Linear search
Binary search
Sorting
Stable sorting
Unstable sorting
Summary
Further reading
Other Books You May Enjoy
Leave a review - let other readers know what you think
Preface
Rust is a powerful language with a rare combination of safety, speed, and zero-cost abstractions. This Learning Path is filled with clear and simple explanations of its features along with real-world examples, demonstrating how you can build robust, scalable, and reliable programs.
You'll get started with an introduction to Rust data structures, algorithms, and essential language constructs. Next, you will understand how to store data using linked lists, arrays, stacks, and queues. You'll also learn to implement sorting and searching algorithms, such as Brute Force algorithms, Greedy algorithms, Dynamic Programming, and Backtracking. As you progress, you'll pick up on using Rust for systems programming, network programming, and the web. You'll then move on to discover a variety of techniques, right from writing memory-safe code, to building idiomatic Rust libraries, and even advanced macros.
By the end of this Learning Path, you'll be able to implement Rust for enterprise projects, writing better tests and documentation, designing for performance, and creating idiomatic Rust code.
This Learning Path includes content from the following Packt products:
Mastering Rust - Second Edition by Rahul Sharma and Vesa Kaihlavirta
Hands-On Data Structures and Algorithms with Rust by Claus Matzinger
Another random document with no related content on Scribd:
ettekä ymmärrä, kun te kuulette merenhenkien toistavan ulapan äärillä tuskani, ahdistukseni, hulluuteni iankaikkisen huudon: — Kalypso, ihana ja tunnoton — hän joka lupaa minulle kuolemattomuuden ja ikuisen nuoruuden lahjan hyväilläkseen minua syöjätär-rakkaudella ja imeäkseen voimaani aikojen loppuun — hän on nostanut luonnon minua vastaan, eroittanut minut haahdettomin rannoin ja poluttomin merin kaikesta, mitä minä ikävöin, ja ruoskinut minua ytimiin saakka kaipauksella, joka on raateleva, turha ja toivoton ja kuolemaa hirvittävämpi.
PARTAALLA
Minä pelkään huoneessani. Minä pelkään ikkunaa ja ihmisvarjoja, joita kuin liskoja, matelijoita se seiniin heijastaa.
Minä pelkään katsoa oveen. Ovi aukee pimeään — ripa kääntyä vois ja tulla ne joille ei nimiä mulla, ne joita mä unissa nään…
Ja myöskin seiniä pelkään.
Näen äkkiä vavahtain: nehän mitään eivät kestä, nehän ketään eivät estä — ovat himmeä seitti vain.
Kuin vieraan hengitys, yöllä joka lapsen säikyttää, niin lävitse seinieni, minut nauliten vuoteelleni, Jokin hiipii, jota en nää.
Hänen — Kauhean läsnäolon minä tunnen. Tunnen sen.
Ja henkiä vartiossa on huoneessani, jossa minä enää elä en.
Ja tuskin hengitänkään.
Olen jähmetys, pelko vain.
Sana äänetön: Armahtakaa!
Sokon tuijotus luomien takaa yli kaikkeus-ulappain,
jotk' ajatukseni vasta tänä hetkenä aavistaa.
Hätäsignaali: Missä, missä on väylä löydettävissä?
Ja onko Jumalaa? —
Ei kukaan, kukaan vastaa. — Kuin vierelle vuotehen kävis Kuolema otaa nostain.
Kuin kaukaa, kaukaa jostain sois pauhina kuilujen.
AUTIO MAA
Sieluni maa on ääretön niinkuin Aasia, autio jäämeren lailla. Harmaata hiekkaa, hiekkaa ja harmaita paasia kaikkea kasvua vailla.
Aikoja sitten jäljet on karavaanien hiekka ahminut siellä.
Kangastus mikään ei näy luoksensa maanien katseen tyhjällä tiellä.
Sieluni maahan pilvi on varjon heittänyt kauas lännestä itään. Viimeinen lintu siivellä päänsä on peittänyt. Ei ole elävää mitään.
LAPSEN KEHTO
Lapsen kehto — valtakunta suurin: siinä nukkuu pieni äärettömyys.
Salaperäinen on kehto keinuessaan: siinä tuuditellaan tulevaisuus. Siinä odottavat kapaloissaan kaikki voimat, kaikki tapahtumat, kaikki viattomuus, kaikki synnit, koko mystillinen ihmiselo.
Vaviskaamme lasta, lapsen kättä. Hän on kerran punnitseva meidät. Lapsi leikkii huolettomin käsin nimillämme unohduksen leikin.
PALLOKENTÄLLÄ
Näin: pallokentän laitaan eräs rampa poikanen oli seisahtanut alle sen suuren lehmuksen.
Hän seisoi nurmikolla, nojas kainalosauvoihin, pelin tiimellystä katsoi hän silmin kuumeisin.
Yli aurinkoisen hiekan, johon lehmus varjon loi, moni riemukas huuto kiiri, moni kirkas nauru soi.
Pojat juoksivat notkein säärin yli pallokentän sen. Eräs seisoi hievahtamatta, eräs raajarikkoinen.
Mut hänkään totisesti ei muistanut sauvojaan. Oli haltioitunut hehku hänen kalpeilla kasvoillaan.
Ilost', innosta värähtelevän
hänen sieraintensa näin
joka kerta, kun maila pallon löi puidenlatvoja päin.
Rajaviivan takaa milloin
joku uskalsi juosta pois, oli niinkuin lehmuksen alta eräs myöskin juossut ois —
kuin jättänyt ramman ruumiin olis sielu poikasen ja syöksynyt kilpasille kera toisten, riemuiten.
Hän askelen astui — — mutta kuin unesta havahtain näki itsensä… Oikea jalka oli kuihtunut tynkä vain.
Pojat juoksivat notkein säärin
yli pallokentän sen, mut lehmuksen alla seisoi
eräs raajarikkoinen,
joka, ruumis tärisevänä, iho harmaana kääntyi pois kuin ruskean nutun alla sydän pakahtunut ois. —
Yhä riemukas huuto kiiri, yhä kirkas nauru soi yli aurinkoisen hiekan johon lehmus varjon loi.
PILVILAULU
Hetket liitävät niinkuin pilvet vainioitten yli. Kaikkien pilvien takaa aukee ahnas Tyhjän syli.
Ei ole mitään armahdusta
sille, mi elää tohti, sille, mi lentää perhossiivin
Päivän silmiä kohti.
Mikä on rientänyt korkeimmalle, korkeimmalta se putoo.
Kuolema niittää vainionsa.
Lukki verkkonsa kutoo.
MARTTYYRIT
Näen heidät ylitse ajan ja paikan: kivitettyinä, ristinpuussa, rovioilla ja giljotiinilla, kiväärinpiippujen edessä ja sähkötuoleissa. Heillä on yllänsä harmaa vanginpuku tai kirjava kaapu. Ja sotamiehet heittävät arpaa siitä. Heidän on kuoltava, jotta me emme kuolisi.
Katso — he loistavat: he ovat hiili ja kytevät sielusta sieluun, he ovat soihtu ja valaisevat aikojen kuilua, he ovat vaskinen käärme ja veri pihtipielissä ja sateenkaari vedenpaisumuksen yllä.
Heidän kuolemansa elämä on loppumaton. Heidät haudataan koko maailman povelle, tulevien aikojen syliin.
PALAVA LAULU
Polun talvisen päähän päätyi ja hangelle jääksi jäätyi
eräs vaeltaja täältä.
— Mut laulu soi hänen päänsä päältä.
Se soi ja — hulmuten paloi.
Ja nukkujan otsalle valoi se seppelen tulta.
Tuli taivaalle nous. Jäi maahan multa.
HOLLANTILAINEN
Näit edessäsi unet kultaiset kuin tornit, uponneina aallon alle.
— Nyt takanas on päivät mennehet kuin laivan vanat, kuolleet ulapalle.
Öin ylläs, allas tähtiparvi on kuin verkon silmukoissa tuhat kalaa. Mut kuolleen-harmaa, tyhjän-toivoton on meren erämaa, kun aamu palaa.
Niin sadat ajast'ajat vaeltain samosit meren salaisuutta kohti.
Edessä silmiesi hourivain se paetessaan väikkyi — Tyhjään johti.
Et aavain kimallusta vanginnut, ei tähtiarkuin lastattuna laivas.
Oi unten-kalastaja, uupunut oot oma varjos. Sua ilkkuu taivas.
— Mut yhä edessäsi kimmeltäin on merta, kaupunkeja aallon alla.
Käy kätes ruoriin: keula niitä päin!
Taas sata vuotta kuljet ulapalla.
POIKANI
Minun poikani — syntymätön ja uneksittu vain — tänä hetkenä hiljaisena olet luonani majassain.
Työpöytäni reunaa vasten näen leukasi, pikkumies.
Olet ollut siinä jo hetken tahi kauankin, kukaties.
Mua suuret lapsensilmäs puronkirkkaina katsovat. Kovin avuttoman kätes sinä minulle ojennat.
Sanot hiljaa sanan: Isä. Ei mitään enempää. Kun tahdon tarttua kätees, se äkkiä häviää.
Mut on kuin näkymättään yhä kutsuis se: Tännepäin! — Minun poikani, silmissäsi oman ikuisuuteni näin,
sen ainoan, joka pysyy, kun itse lahoan, ja sen ikuisuuden vuoksi minä sinua rakastan.
Minä tunnen: Kuolema kerran kun vie minut Tyhjää päin, jos pienet sormesi silloin olen tunteva kädessäin
ja jos, poikani, virkat vielä sanan pienen, hiljaisen, en pelkää astua enää Olemattoman piiriin, en.
KOHTALO
Sinun voimasi kietoi minut — sinä tuntemattomin — kuin ois mua kahlehtinut käsi julman enkelin.
Kuin hartioilleni pantu olis paino vuorien ja otsalleni rantu kova taottu, rautainen.
Oli päiväni kuin tuhat vuotta, kun painin kanssas sun.
— En paininut kanssasi suotta: tänä päivänä siunaat mun!
Tänä päivänä tunnen vasta: kätes oikein lyönyt on.
Nyt en lakkaa siunaamasta sua, voima Kohtalon:
Teit silmäni janooviksi, nälän kasvatit sydämeen, minut uuvutit varjoin — siksi olen valmis kirkkauteen.
Tänä päivänä armon annat taas virrata kädestäs. Kuin vaakalintu kannat minut riemuun siivilläs.
MINÄ
(Ernst Josephson)
Nämä silmät itkevät verta vuoks syntien pusertuvaa, vuoks kaiken, mi haavoitti kerta sydänparkaa — ja haavoittaa.
Tämän kohtalon syy ei kukaan. Elon virtaa tottelen vain oman tulvani suunnan mukaan, padot, telkimet musertain.
Olen huoleti kulkeva suureen maan sylihin paluutien; epäjumalten rovion juureen nimen, maineen nauraen vien.
RAKKAUS
(Eduard Mörike)
Kun armaan suuta suutelet, sun janoos ei se riitä: jos vettä seulaan kaatanet, ei täyty seula siitä. Ja vaikka tuhatvuotiset ois suudelmas, tai ikuiset, saat niukasti sa niitä!
Sun rakkautes aaltoilee ain' uusin halun muodoin. Ja huulet, suun, mi suutelee, se punaa verenvuodoin.
Ja tyttö vaikka vapisee kuin vohla veitsen alla, hän pyytää, silmin rukoilee: — Kivulla suuremmalla!
Niin on. Ja samoin ollut jo on alust' elämän. Niin rakasti jo Salomo, ei muuta voinut hän.
YÖSSÄ
Kohu tuulen ja sateen ja kaukaisen raitiovaunun. Ei mitään muuta.
Katukuilun toisella puolen on kahdessa ikkunassa hyvin keltainen valo.
Ja huuruista ruutua hipoo jonkun häilyvän oksan varjo kuin ihmisen käsi.
— Mutta keskellä pimeyttä minun huoneeni elää: kuin simpukka syvyydessä tai sykkivä sydän.
Se on saiturin lipas: salaista iloa täynnä.
Sen ilma on kuiskauksista vapiseva ja katseista kirkas niinkuin kasteinen aamu.
Sen matolla leikkii vielä pienten jalkojen muisto.
Ja vuoteella viipyy kuva poissaolevan, nuoren, lämpimän ruumiin niinkuin Kauneus itse.
Ja katsomattani näen oven äsken nielemät kasvot ja värisen niitä.