Rust experiments Entry: Rustboot Date: Sun Sep 15 17:30:39 EDT 2013 https://github.com/charliesome/rustboot Entry: Getting stuck on iterators Date: Sat Sep 21 21:29:06 EDT 2013 Seems the language has changed quite a bit recently. Compiling today's version... Doesn't change much except for breaking my code.. Switched back to 0.7 and wrote 'range' manually as in [1] [1] https://github.com/charliesome/rustboot/blob/master/main.rs Entry: 4 million task switches per second is a bit much Date: Sat Sep 21 22:57:01 EDT 2013 Running salea at 4MHz, with each byte going through the channel. It chokes on that.. But it looks like it can handle 100kHz. Preliminary conclusion: tasks are not state machines.. A little disappointing but not really surprising. Entry: Buffered channels Date: Sat Sep 21 23:26:57 EDT 2013 From here[1] it seems that context switches happen as soon as there is a write to a waiting reader. For logic.rs this is too inefficient. How to implement a Port differently such that we can send larger chunks? For the logic analyser it might even make sense to encode events in a differential way. Is Port a trait? -> NO Seems though that it should be possible to just abstract the input of parsers to a trait that allows both ports and state machines. Probably just the iterator interface? static trop_len = 1024 trait Trop { fn vcer(&self); } impl Trop for Port { fn vcer(&self) { self.recv(); } } [1] https://mail.mozilla.org/pipermail/rust-dev/2013-May/004127.html Entry: Buffered channels : again Date: Sun Oct 6 10:17:54 EDT 2013 Let's do this. A buffered channel needs two ends. How does that map into traits? Probably two traits are needed, and a "constructor" returns an object that supports two traits, but is exposed only one side through each interface? This doesn't seem to be the right approach: trait BufPort { fn recv(&self) -> T; } trait BufChan { fn send(&self, T); } struct WrappedStream { p : Port, c : Chan, } impl BufPort for WrappedStream { fn recv(&self) -> T { self.p.recv() } } -> error: instantiating a type parameter with an incompatible type `T`, which does not fulfill `Send` Need to modify the *endpoints* of a channel, not the channel type itself. Hmm.. Getting the same errors with this: trait BufPort { fn _recv(&self) -> T; } trait BufChan { fn _send(&self, T); } struct WrappedPort { p : Port } struct WrappedChan { c : Chan } impl BufPort for WrappedPort { fn _recv(&self) -> T { self.p.recv() } } impl BufChan for WrappedChan { fn _send(&self, e:T) { self.c.send(e); } } Start simpler? Looking around the docs, I ran into `SendDeferred' http://static.rust-lang.org/doc/0.8/std/rt/comm/trait.SendDeferred.html It needs: use std::rt::comm::SendDeferred; It doesn't seem to solve the performance issue. Next? Go back to the prev buffer impl and figure out what the error means. Check this: "Implementation for ChanOne where " from http://static.rust-lang.org/doc/0.8/std/comm.html The "Send" trait is mentioned here as a special trait, implemented by the compiler: http://pcwalton.github.io/blog/2012/08/08/a-gentle-introduction-to-traits-in-rust/ "Other special traits include send, which is a trait that indicates the type is sendable" So I misread. This is not a channel constraint, but a sendable data constraint. With annotation fixed: trait BufPort { fn recv(&self) -> T; } trait BufChan { fn send(&self, T); } struct WrappedPort { p : Port } struct WrappedChan { c : Chan } impl BufPort for WrappedPort { fn recv(&self) -> T { self.p.recv() } } impl BufChan for WrappedChan { fn send(&self, e:T) { self.c.send(e); } } Entry: #[start] and/or #[no_std] Date: Thu Nov 14 01:35:43 EST 2013 https://github.com/pcwalton/zero.rs : This is deprecated and is no longer maintained. It is no longer necessary to use this to achieve runtime-less operation; just use #[start] and/or #[no_std] and avoid the runtime. http://osdir.com/ml/rust-mozilla-developemnt/2013-10/msg00032.html : Entry: #[no_std] Date: Mon Dec 9 21:40:05 EST 2013 Doesn't work out of the box. https://github.com/thestinger/rust-core/blob/master/example.rs Entry: Project Date: Tue Dec 10 15:07:40 EST 2013 What am I building? Support code for the synth. A sound playback / recording engine? I don't have specs for this, so probably not a good candidate. What do I have specs for? A state machine OS? Entry: FFI Date: Sun Aug 10 21:47:30 EDT 2014 I'd like to make some bindings to zl (to be) used in PDP / libprim / packetforth.. FFI seems really simple. [1] http://doc.rust-lang.org/guide-ffi.html Entry: No more segmented stacks Date: Mon Aug 11 00:15:15 EDT 2014 https://mail.mozilla.org/pipermail/rust-dev/2013-November/006314.html Entry: Cross compiler ARM Date: Mon Aug 11 12:26:42 EDT 2014 ./configure --target=arm-unknown-linux-gnueabi && make rustc --target=arm-unknown-linux-gnueabi --linker=arm-linux-gnueabi-gcc hello.rs [1] https://mail.mozilla.org/pipermail/rust-dev/2014-February/008556.html Entry: Byte pointer to rust array? Date: Tue Aug 12 20:12:08 EDT 2014 Is it possible to access a raw byte segment as a rust array? I don't see a way to do this so let's just copy. How to create an unintialized array? http://www.reddit.com/r/rust/comments/29ymbx/a_macro_to_fill_a_fixed_length_array/ Entry: Rust on ARM Date: Fri Sep 12 21:51:49 CEST 2014 Adapted from [1] See also [2] # rust-compile-arch.sh arm-unknown-linux-gnueabihf ARCH=build-arm-none-eabi mkdir build-$ARCH cd build-$ARCH ../configure --target=$ARCH --prefix=$HOME/local/rust-$ARCH make -j8 && make install Now this gives both: lib/rustlib/arm-unknown-linux-gnueabihf/lib/libstd-e32fa708-0.11.0.so: ELF 32-bit LSB shared object, ARM, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x5e4e77d08ff8b891de8b2de6111b670b34592974, not stripped lib/libstd-e32fa708-0.11.0.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=0x20f6f1b890229f5ae1164e60a00e4f5bc72d63ec, not stripped How to invoke the ARM compiler? $ bin/rustc --target=arm-unknown-linux-gnueabi /tmp/test.rs /tmp/test.rs:1:1: 1:1 error: can't find crate for `std` /tmp/test.rs:1 fn main() { Not using --target compiles a native binary. EDIT: Read [1]: to invoke PATH=$HOME/local/rust-arm-unknown-linux-gnueabihf:$PATH rustc -C linker=/usr/bin/arm-linux-gnueabihf-gcc -C target=arm-unknown-linux-gnueabihf test.rs [1] https://gist.github.com/mcpherrinm/11239842 [2] http://zwizwa.be/darcs/pool/bin/rust-compile-arch.sh Entry: armboot Date: Sat Sep 13 11:06:19 CEST 2014 The way it works for armboot[1] is to output LLVM IR and compile that manually. This means no std. So it seems the main point for "./configure --target" is to cross-compile the libraries tied to a particular processor,system,abi. Questions: - what is the difference between *.so in lib/ *.so and *.rlib in lib/rustlib/x86_64-unknown-linux-gnu/lib/ lib/rustlib/arm-unknown-linux-gnueabihf/lib/ [1] https://github.com/neykov/armboot/blob/master/Makefile [2] http://comments.gmane.org/gmane.comp.lang.rust.devel/8476 Entry: Crosscompile Date: Sat Sep 13 13:48:34 CEST 2014 ./configure --target=arm-unknown-linux-gnueabi && make rustc --target arm-unknown-linux-gnueabihf -C linker=arm-linux-gnueabihf-g++ hello.rs test.rs:1:1: 1:1 error: can't find crate for `std` Adding the path explicitly seems to work: rustc --target arm-unknown-linux-gnueabi -L/home/tom/git/rust/build/20140913-114516/x86_64-unknown-linux-gnu/stage2/lib/rustlib/arm-unknown-linux-gnueabi/lib/ -C linker=arm-linux-gnueabi-g++ /tmp/test.rs Entry: pyla Date: Mon Sep 15 01:13:41 CEST 2014 Maybe I should add rust support to the pyla code. Just to give a point of comparison. What it will feel like to write state machines in rust.. The combination with BeagleLogic would be nice as well. Entry: armboot Date: Tue Sep 30 20:01:01 CEST 2014 Allow C types. Is this unsafe? #![allow(ctypes)] Don't use the standard library, see [2]. #![no_std] Open some feature gates. "mark certain features as either deprecated or experimental and subject to change" [3] #![feature(macro_rules)] see [4] #![feature(globs)] #![feature(lang_items)] Found these files from the name ./libsyntax/ext/tt/macro_rules.rs ./librustc/middle/lang_items.rs #![crate_id="blinky#0.3.2"] [1] https://github.com/neykov/armboot [2] http://doc.rust-lang.org/guide-unsafe.html [3] http://cmr.github.io/blog/2014/01/12/the-state-of-rust-0-dot-9/ [4] http://rustbyexample.com/staging/macros.html Entry: browsing rust code Date: Tue Sep 30 20:18:45 CEST 2014 It's not small: [zwizwa_2014-09-13] tom@zni:~/git/rust/src$ cat `find -name '*.rs'` | wc 452236 1835277 16678526 [zwizwa_2014-09-13] tom@zni:~/git/rust/src$ for i in *; do echo -e "$(find $i -name '*.rs' | wc -l)\t$i"; done 0 compiler-rt 7 compiletest 0 doc 1 driver 0 etc 1 grammar 0 gyp 0 jemalloc 7 liballoc 1 libarena 0 libbacktrace 18 libcollections 49 libcore 33 libcoretest 4 libdebug 1 libflate 1 libfmt_macros 1 libfourcc 1 libgetopts 1 libglob 2 libgraphviz 11 libgreen 1 libhexfloat 1 liblibc 3 liblog 17 libnative 5 libnum 10 librand 2 librbml 10 libregex 1 libregex_macros 1 librlibc 155 librustc 13 librustc_back 3 librustc_llvm 22 librustdoc 20 librustrt 20 librustuv 1 libsemver 6 libserialize 75 libstd 18 libsync 66 libsyntax 6 libterm 2 libtest 1 libtime 5 libunicode 1 liburl 1 libuuid 0 libuv 0 llvm 0 README.md 0 rt 0 rustllvm 0 snapshots.txt 3613 test Entry: Unsafe code Date: Tue Sep 30 20:59:13 CEST 2014 http://doc.rust-lang.org/guide-unsafe.html Entry: pyla - streams Date: Wed Oct 1 10:59:27 CEST 2014 So, what about writing logic analyzer core routines in rust in a functional style, and then bind them to loops over buffers? THE single most important (and simple!) problem I keep encountering. Not so much about how to write the nitty gritty, but how to organize it so it stays efficient. If I understand correctly, Rust should be able to do this. Start with (s,i)->(s,o) First problem is parametric polymorphism. A generic iterator should not care about the atom types, just the containers. Let's have a look at the Iterator library[1]. [1] http://doc.rust-lang.org/std/iter/trait.Iterator.html Entry: Project Date: Tue Jan 20 14:38:45 EST 2015 Audio controller in rust. Something that can run on an embedded device with touchscreen. I want dancing waveforms on the screen, but don't need 3D. The problem has always been widgets. So let's fix that. Entry: gui requirements Date: Tue Jan 20 16:50:18 EST 2015 - smooth. it's fucking 2015. no more excuses for not having smooth guis that update at full framerate and have no tearing. - this means double buffering. I'd also like to use this for embedded systems, so allow for selective redraw. - So start with an OpenGL application that syncs to the display and uses double buffering. - Should have midi learn Entry: picking up again Date: Fri Jan 30 12:14:20 EST 2015 Not clear why io is now old_io. https://www.reddit.com/r/rust/comments/2tdudy/psa_io_old_io/ Entry: rust logic: external iterators Date: Fri Jan 30 14:32:41 EST 2015 It seems easiest to abstract things as external iterators. So let's abstract the buffer sequence flattening as an iterator. there is already flat_map() http://doc.rust-lang.org/core/iter/trait.IteratorExt.html Entry: Functional vs. Mutation Date: Fri Jan 30 15:21:28 EST 2015 So for the logic analyzer, and important question is to use in-place update or not. Is a rust "fold" smart enough to use in-place update for an object that stays mostly the same? It seems that even if the fold would be smart enough to take care of performance concerns, there is still the element that a mutating algorithm is a lot easier to read and write (less code!). I think (hearsay) this is also part of what Lens is doing for Haskell: provide a mutable interface for small updates. Entry: General idea for logic analyzer Date: Fri Jan 30 15:28:21 EST 2015 For performance reasons it's important to keep data in chunks. This translates to a nested iterator for the outer management layer: sequence of buffers of bytes. The internal layer does not bother with protocols. Encode protocols in byte streams. For performance reasons, all state is private and updated in-place. EDIT: see lars project Entry: Checking inner loops Date: Sun Feb 1 15:48:23 EST 2015 So I have some code that iterates over a trait operation. AFAIK this should be possible to optimize. How to find that loop in llvm IR or asm? Entry: printing types Date: Sun Feb 1 20:46:20 EST 2015 Just a note that if you want to quickly determine the type of an expression, you can do let () = { /* my expression here */ } [1] https://www.reddit.com/r/rust/comments/2h26cj/functions_returning_iterators/ Entry: iterators and associated types Date: Sun Feb 1 20:51:20 EST 2015 wtf is this? Why not simply a type parameter? pub trait Iterator { type Item; // associated type ... } and pub trait Iterator { // parameter ... } [1] https://www.reddit.com/r/rust/comments/2mdcyy/associated_types/ Entry: Iterator Date: Sun Feb 1 20:55:30 EST 2015 What is the difference between: expected `core::iter::Iterator`, found `core::slice::Iter<'_, u8>` A type is not a trait. [1] https://www.reddit.com/r/rust/comments/2l2c2r/beginner_iteratorvector_problem/ Entry: hours Date: Sun Feb 1 21:13:29 EST 2015 Entry: Iterators Date: Sun Feb 1 21:25:41 EST 2015 Seems that passing around iterators is a mess. What about passing around things that can produce iterators? Is there a trait for the .iter() method? Entry: Sinking in Date: Sun Feb 1 23:37:55 EST 2015 So Iterator is a trait, not a type. Apparently it's not (yet) possible to have a function be typed to return a trait. [1] https://stackoverflow.com/questions/26953280/how-to-create-a-non-consuming-iterator-from-a-vector Entry: Not copying iterators Date: Sun Feb 1 23:41:10 EST 2015 One way seems to be to just create iterators from iterators. I.e. map, filter, fold. Let's look at filter and mimick its operation. This still has the problem of needing to type return values.. It seems simplest to just implement the iterator Trait for all processors, and use a pull-style anyway. [1] https://www.reddit.com/r/rust/comments/2h26cj/functions_returning_iterators/ Entry: Switching to Iterators and pull style Date: Sun Feb 1 23:51:52 EST 2015 Seems to fit better with the way rust treats sequences. Entry: expected bound lifetime parameter , found concrete lifetime Date: Mon Feb 2 11:21:40 EST 2015 http://stackoverflow.com/questions/24847331/rust-lifetime-error-expected-concrete-lifetime-but-found-bound-lifetime Entry: Reporting bug Date: Mon Feb 2 11:49:44 EST 2015 To reproduce: https://github.com/zwizwa/lars d0a9cae2d174c181f80a3e2716118dd59945be78 bug compiling la.elf ( make la.elf ) This is on Debian wheezy/jessie/sid cocktail. rustc 1.0.0-nightly (1d00c545e 2015-01-30 19:56:34 +0000) binary: rustc commit-hash: 1d00c545ede609b9d43fdf9f252c15da5a66dac7 commit-date: 2015-01-30 19:56:34 +0000 host: x86_64-unknown-linux-gnu release: 1.0.0-nightly [master] tom@zoo:~/lars$ make la.elf RUST_BACKTRACE=1 rustc la.rs -o la.elf ERROR:rbml::reader: failed to find block with tag 7 error: internal compiler error: unexpected panic note: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: http://doc.rust-lang.org/complement-bugreport.html note: run with `RUST_BACKTRACE=1` for a backtrace thread 'rustc' panicked at 'explicit panic', /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/librbml/lib.rs:266 stack backtrace: 1: 0x2b9353530870 - sys::backtrace::write::h26b40214a7757117H8t 2: 0x2b9353553be0 - failure::on_fail::h7a79bf921b6662fbzkB 3: 0x2b93534c01f0 - rt::unwind::begin_unwind_inner::hfe1c0e12f5e834cfAZA 4: 0x2b935a46b550 - rt::unwind::begin_unwind::h13771489483523584678 5: 0x2b935a46a2e0 - reader::get_doc::hca9c74691b431218nLa 6: 0x2b93553feac0 - metadata::decoder::item_type::h11e3fdce04437c2aTqh 7: 0x2b935540fa40 - metadata::decoder::get_type::h81f5136878596756uDh 8: 0x2b93553be9b0 - metadata::csearch::get_type::h9b0725336787e95fjuk 9: 0x2b9353fb38d0 - collect::CollectCtxt<'a, 'tcx>.AstConv<'tcx>::get_item_type_scheme::ha84927afd1cd11a416u 10: 0x2b9353fa2550 - astconv::ast_path_to_ty::h5eef35501e32996d3It 11: 0x2b9353fa3a40 - astconv::ast_ty_to_ty::closure.32670 12: 0x2b9353f3d7f0 - astconv::ast_ty_to_ty::hdfd5055274123a4bN9t 13: 0x2b9353f9c060 - vec::Vec.FromIterator::from_iter::h13503769950079175686 14: 0x2b9353f99cc0 - astconv::convert_angle_bracketed_parameters::h9025012b833df2f4Vit 15: 0x2b9353f3d260 - astconv::ast_path_substs_for_ty::hb223d380e0653eb777s 16: 0x2b9353fa2550 - astconv::ast_path_to_ty::h5eef35501e32996d3It 17: 0x2b9353fa3a40 - astconv::ast_ty_to_ty::closure.32670 18: 0x2b9353f3d7f0 - astconv::ast_ty_to_ty::hdfd5055274123a4bN9t 19: 0x2b9353f9cb70 - astconv::convert_ty_with_lifetime_elision::h6aef1296b36bbcec2mt 20: 0x2b9353fa78d0 - astconv::ty_of_method_or_bare_fn::hfbbddbe9dd8fd2d8Dtu 21: 0x2b9353fa7750 - astconv::ty_of_method::h90bdcfba9a641a98Zru 22: 0x2b9353fcba40 - collect::convert_methods::ty_of_method::h37cc71cdb4ced048svv 23: 0x2b9353fb94e0 - collect::convert::hbd254ededfa34065yyv 24: 0x2b9353ff3670 - check_crate::closure.33797 25: 0x2b9353ff15b0 - check_crate::hd5b0ce5ac42bd86cIEz 26: 0x2b935311bf50 - driver::phase_3_run_analysis_passes::h3a3da09b2eae9713NFa 27: 0x2b9353103330 - driver::compile_input::h802d2a6759ac022fBba 28: 0x2b93531c9230 - run_compiler::h4517938d3296cfc5l9b 29: 0x2b93531c78c0 - thunk::F.Invoke::invoke::h5452441173088021345 30: 0x2b93531c67f0 - rt::unwind::try::try_fn::h8490101008730471441 31: 0x2b93535bef60 - rust_try_inner 32: 0x2b93535bef50 - rust_try 33: 0x2b93531c6aa0 - thunk::F.Invoke::invoke::h13338196279056651375 34: 0x2b93535403b0 - sys::thread::thread_start::h395b8c6815673c5cN3w 35: 0x2b935950bfe0 - start_thread 36: 0x2b9353b73c99 - __clone 37: 0x0 - make: *** [la.elf] Error 101 http://doc.rust-lang.org/complement-bugreport.html Entry: unboxed closures Date: Mon Feb 2 14:02:40 EST 2015 https://www.reddit.com/r/rust/comments/2lo6yt/closures_vs_unboxed_closures/ Entry: Function pointers Date: Mon Feb 2 14:27:41 EST 2015 So I want to parameterize a function with a kind of continuation, i.e. some sink that takes a value while i'm going through a loop. How does it know its state, and does the function type need to reflect this? There are a couple of options: closures and the call operators [1][2]. (expected fn pointer, found closure) [3] [1] http://doc.rust-lang.org/std/ops/trait.Fn.html [2] http://doc.rust-lang.org/std/ops/trait.FnMut.html [3] https://stackoverflow.com/questions/24979454/differences-between-fn-and-in-type-for-an-array-of-functions [4] https://www.reddit.com/r/rust/comments/2lpdvn/callbacks/ Entry: trait objects Date: Mon Feb 2 15:00:58 EST 2015 [1] https://huonw.github.io/blog/2015/01/peeking-inside-trait-objects/ Entry: frustrated Date: Mon Feb 2 16:33:40 EST 2015 * Maybe this is for another time when I have some more patience. The type system is complex and takes a long time to absorb in my current state of mind. * There is no way around knowing all (most?) there is to know about the trait system to do any reasonable abstraction. * It is hard to find documentation that is up-to-date. Again, no patience to weed through all this. Maybe wait for 1.0? Maybe wait to relax and go with the flow.. Entry: Rust Types Date: Mon Feb 2 16:55:20 EST 2015 [1] http://cosmic.mearie.org/2014/01/periodic-table-of-rust-types/ Entry: Traits Date: Mon Feb 2 17:06:33 EST 2015 So it seems that to use traits in arguments (or return types) the options are: - Use trait pointers, which will resolve type dispatching dynamically. - Write the function as a trait, which allows type-dispatch at compile time. Entry: traits Date: Mon Feb 2 17:11:11 EST 2015 So basically it seems that a lot of programming in rust needs generics. Even for simple callbacks it's necessary to implement behavior as a trait or resort to trait objects, delegating type dispatch to run time. Two points where this gets a little annoying: - Iterators - Closures: Fn / FnMut Traits seem to work due to the interplay of parameterized structs and constraints on the trait and implementation. Elaborate. Entry: slices Date: Mon Feb 2 20:41:11 EST 2015 &[T] is a fat pointer (pointer + size), implemented by std::raw::Slice. https://stackoverflow.com/questions/25027751/is-t-literally-an-alias-of-slice-in-rust Entry: "Explicit lifetime bound required" Date: Mon Feb 2 21:32:16 EST 2015 hint: I've seen many cases where a trait was accidentally used instead of a regular type and there was no obvious hint as to why a lifetime bound would be required at all. Don't confuse types and traits. In: pub fn stream<'a,I>(i: I) -> Stream<'a,I> where I:Iterator, { ... } The I can't just be substituted. It seems that the where clause means something like I implements the trait ... These are called Bounds[2]. [1] https://github.com/rust-lang/rust/issues/16948 [2] http://rustbyexample.com/bounds.html Entry: generic programming in rust Date: Mon Feb 2 22:19:17 EST 2015 - create a struct to contain state data - have the struct implement a trait - wrap the struct in a function that instantiates it - call trait methods on the result of that function call Entry: still running into corner cases with iterator Date: Tue Feb 3 13:59:49 EST 2015 /* It's not possible to type ther return value as an Iterator because that's a trait so would either require trait objects (which seem to cause lifetime problems) or implement the Iterator trait using a struct which requires a lot of boiler plate. It seems easier to just type the functions with the concrete return type (that implements the Iterator trait). https://www.reddit.com/r/rust/comments/2h26cj/functions_returning_iterators/ */ use std::iter::{Counter,Take,Map,count}; use std::ops::{Range}; //use core::ops::{Fn}; extern crate core; fn bits_bit(c: &Config, v: usize) -> Take> { count(v,0).take(c.period) } fn bits_frame(c: &Config, v: usize) -> Map,Fn(usize)->usize> { (0us..c.nb_bits+2).map(|&:bit:usize| (((v | (1 << c.nb_bits)) << 1) >> bit) & 1) } fn bits_samples(c: &Config, data: &Vec) -> Vec { data.iter().flat_map(|&x| bits_frame(c, x)).collect() } Entry: flat_map Date: Thu Feb 5 01:46:26 EST 2015 01:44 < doelie> hi, any idea why this gives a lifetime error: 01:44 < doelie> fn main() { for _ in (0u8..10).flat_map(|x| (0u8..10).map(|y| x+y)) {} } 01:44 < lfairy> since contributors disagree on that 01:44 < eddyb_> doelie: flat_map stores its result 01:45 < eddyb_> doelie: maybe move |y| x+y will work for the inner closure 01:45 < doelie> eddyb_: thanks for the pointer 01:46 < eddyb_> doelie: the result of calling the closure you gave to it, to be precise (which in this case, contains another closure, which borrows x by default) have a look at flat_map implementation. Entry: UI on embedded box Date: Fri Feb 13 19:26:49 EST 2015 As a UI, what is realistic to expect? - OpenGL ES - touch screen Maybe best not to worry about it too much and just go ahead with linux / OpenGL. Otoh directFB might be interesting. Dev box? Let's just stick with OpenGL and mouse for now. Entry: cross-compile Date: Sun Feb 15 17:27:10 EST 2015 BUILD=build-20150215 PREFIX=$(readlink -f ~/lib/rust/$BUILD) LD_LIBRARY_PATH=$PREFIX/lib mkdir -p $PREFIX mkdir -p ~/git/rust/$BUILD cd ~/git/rust/$BUILD ../configure --target=arm-unknown-linux-gnueabi --prefix=$PREFIX && make -j4 && make install Entry: trait objects Date: Sun Feb 15 18:43:40 EST 2015 Composing iterators from higher order functions works well, as long as you keep them "inside" a function. data_in.iter() // expand data word into bits FIXME: add frame strobe, polarities .flat_map(|&data| (0..nb_bits).flat_map(move |shift| { let bit = (data >> (nb_bits - 1 - shift)) & 1; // expand bit into clocked bit sequence (0..2).map(move |clock| (clock << c.clock_channel) | (bit << c.data_channel)) })) // oversample .flat_map(|bus| (0..period).map(move |_| bus))) Trying to turn them into trait objects becomes problematic[1]: You can't put anything meaningful in **what goes here**. The closure you define has a compiler-generated type that you can't name (that is, until abstract return types are implemented). Creating an iterator object should be possible if the closures are boxed as well, but requires a wrapper struct for the Fn trait so at this point, the simplest way to reuse that code is to make a macro. [1] https://stackoverflow.com/questions/27496278/how-to-return-a-generic-map-struct Entry: Moving Vec out of mutable borrowed object. Date: Tue Feb 17 18:09:06 EST 2015 18:07 < doelie> Hi. I have Vec living inside a borrowed mutable object. I'd like to move this vec somewhere and replace it with a new one. Rust doesn't let me move it because owner is borrowed. Is there a way to "copy and empty" into a new vector without actually copying the data? 18:07 <@kmc> doelie: mem::replace 18:07 < doelie> thanks! http://doc.rust-lang.org/std/mem/fn.replace.html Entry: graphics Date: Fri Feb 20 21:25:43 EST 2015 glium seems the best way in. [1] https://tomaka.github.io/glium/glium/index.html Entry: opengl terminal emulator Date: Fri Feb 20 21:35:16 EST 2015 Not really what I'm looking for. What I want is a notebook style thing. I.e. what is possible in emacs, but using widgets. Maybe drracket is the thing to go for? The thing is, what I want to do is really simple. Just give me a black-and-white frame buffer and I'll figure it out. https://www.reddit.com/r/programming/comments/1dsjyj/i_wrote_an_open_source_terminal_emulator_which/ Entry: job vranish on embedded rust Date: Fri Feb 20 23:46:23 EST 2015 http://spin.atomicobject.com/2015/02/20/rust-language-c-embedded/ https://lobste.rs/s/3twwvw/embedded_rust_right_now Entry: intrinsics / volatile Date: Sun Feb 22 20:04:39 EST 2015 http://doc.rust-lang.org/std/intrinsics/ Entry: Rust on STM32F1,4 Date: Mon Feb 23 23:27:36 EST 2015 Seems like it is mostly trivial, as objects can be mixed. Startup can be done in C for now, on top of libopencm3. I just need an application. The app would be a minimal core for running RAI processors on the discovery & AXO boards. Entry: Rust OpenGL stuff Date: Tue Feb 24 01:35:04 EST 2015 Two parts: - glutin: OpenGL context provider - glium: OpenGL high level wrapper Another strain: - gfx-rs: A high-performance, bindless graphics API - glfw: glfw3 bindings - gfx-gl: OpenGL bindings for gfx, based on gl-rs - gl: OpenGL bindings It was heavy on the shaders so maybe that's just how OpenGL is these days? Let's just suck up the examples. Start with the explanation from the author[1]. And the other strain.. which to pick? I really just want raw OpenGL. I have C++ widget code already.. My take: this needs to run on an embedded device eventually. I'm thinking of an LCD screen as an Eurorack module, or a stand-alone box. Let's split it in two parts: - Find an embedded arm board that can host an LCD (touch) screen. No android or apple shit: start from scratch. This would probably need to be OpenGL ES. - Should not be too hard to develop on PC / regular OpenGL and keep portability in mind. [1] https://www.reddit.com/r/rust_gamedev/comments/2mkbs9/gliums_design_choices/ [2] https://gfx-rs.github.io/2014/07/25/intro.html Entry: Too much at once Date: Tue Feb 24 21:51:56 EST 2015 - Libraries are not stable. Hard to get a working example to run. - OpenGL has gotten complicated. This is going to take some time to absorb. So where to start? Either go back to C and stick with the familiar approach or push through to get a working Rust example. Entry: Build failures Date: Tue Feb 24 21:57:05 EST 2015 So building a library and it fails. Probably due to missing dev packages for the C libs, but how to find out? Getting obscure things like: src/khronos_api/src/lib.rs:4:36: 4:68 error: couldn't read src/khronos_api/api/gl.xml: couldn't open path as file (no such file or directory (No such file or directory); path=src/khronos_api/api/gl.xml; mode=open; access=read) src/khronos_api/src/lib.rs:4 pub static GL_XML: &'static [u8] = include_bytes!("../api/gl.xml"); Yeah I can't do this while I'm sick and tired.. Start with just reading this source https://github.com/bjz/gl-rs/blob/master/examples/static_triangle.rs Straightforward red tape.. Entry: Are there any iterators that own an array? Date: Sat Feb 28 20:36:39 EST 2015 I wrote this struct InArr2 { a: [f32; 2], i: usize } fn in_arr2(a: [f32;2]) -> InArr2 { InArr2 { a:a, i:0 } } impl Iterator for InArr2 { type Item = f32; fn next(&mut self) -> Option { if self.i == self.a.len() { return None; } let rv = self.a[self.i]; self.i += 1; return Some(rv); } } Because this (0..2).flat_map(|i| [0,1].into_iter().cloned()); says that [0,1] doesn't live long enough. I think the reason for that is that into_iter() takes a reference, not ownership. I think I understand why. Arrays are a bit special in that they are statically allocated. It seems hard to do things like "turn an array into an iterator" because the storage of the array should actually be inside the iterator in the first place. That is why the above works, but it seems this is hard to do generically. Entry: Ownership woes: trees versus traversals Date: Sun Mar 1 17:32:51 EST 2015 Rust has some rough edges. Most of those can be worked around by finding a simpler solution. Managing ownership isn't always easy. A simple thing to keep in mind is that when you want to order objects in many different ways it is often possible to use one of those orderings as a way to handle the ownership (tree), and implement the other orderings as traversals. Entry: Next Date: Mon Mar 2 00:55:31 EST 2015 Basics are there: - event - draw The rest should be filling in the blanks and maybe doing some reactive stuff. What widgets? Maybe reconstruct a 303 - Pattern sequencer: buttons, sliders, note numbers - VU meter - Waveform display Entry: Pointer Date: Mon Mar 2 00:56:45 EST 2015 Box owned trait object &Trait borrowed trait object Entry: boilerplate Date: Thu Mar 5 01:02:56 EST 2015 Is there a way around this? The type annotation is cumbersome and repeated 3 times: - struct def - constructor - trait implementation struct FIR2 where I:Iterator, T:Clone { last: T, iter: I } fn fir2 (iter: I, init: T) -> FIR2 where I:Iterator, T:Clone { FIR2 { last: init, iter: iter } } impl Iterator for FIR2 where I:Iterator, T:Clone { type Item = (T,T); fn next(&mut self) -> Option<(T,T)> { match (self.iter.next()) { None => None, Some(current) => { let last = mem::replace(&mut self.last, current.clone()); Some((current, last)) } } } } Entry: Picking up again Date: Sun Dec 11 11:07:54 EST 2016 - difference between "extern crate" and "use" https://doc.rust-lang.org/nightly/book/crates-and-modules.html - is "io::" still there? Entry: Rust on ARM Date: Fri Nov 3 12:35:24 EDT 2017 I need something to start with. Rust on ARM without C HAL seems to be the way to go. At least for now. I have a bunch of these kinds of devices and am familiar with the peripherals. http://blog.japaric.io/quickstart/ EDIT: Let's give this a try, but I'm not getting too deep into yak shaving if it doesn't work. The alternative is to get V4L to work on the pi, or on the PC first. - rustup not installed? Actually it is in /root/rust-lang/rustup I had to change things: root@core:~/rust-lang# ./rustup-disable-sudo.sh --channel=nightly It's already different. Looks like rustup.rs and rustup.sh are not the same thing. It is possible to install rust as a user, so let's just do that. lib/rustlib/uninstall.sh to erase the global install then start over $ rustup default nightly # apt-get install binutils-arm-none-eabi libssh-dev $ cargo install xargo $ cargo install cargo-clone $ cargo clone cortex-m-quickstart --vers 0.1.1 Entry: Installing Rust Date: Sun Nov 5 09:54:13 EST 2017 https://www.rust-lang.org/en-US/install.html Entry: Incremental Date: Sun Nov 5 09:56:08 EST 2017 While I am tempted to "throw everything out and start over in Rust", it would probably be not a good idea to do so. Incremental bits. Currently what makes the most sense is to: - Create some .o files to link into an existing STM32F103 build - Create native functions or ports for Erlang EDIT: Get used to building some code without the overhead of booting a uC. Entry: State of no_std Date: Mon Jan 8 00:49:36 EST 2018 https://doc.rust-lang.org/1.11.0/book/no-stdlib.html Entry: Trusted code Date: Sun Jan 21 10:43:33 EST 2018 Thinking a lot about distributed systems and trusted code. Ending up with the idea that the Erlang VM cannot be the trusted base when the remote protocol is used. Instead, a smaller "trusted core" should be built. I'm still finding ways to think about this. It seems that in many cases, architecture requirements imposed by limiting trusted code will conflict with those imposed by functionality. I'm in an impasse, and without breaking the loop by actually building something, there is not going to be any progress. Why rust? - Types - Memory efficient Start with a TCP server. OK I have an example. Now I need a platform. Thermostat would be the place to start. Needed: - NFS boot uboot on colibri board (don't use BB for this) - Rust cross compiler for application NFS boot isn't really necessary, but cross compiler is. Maybe start by eliminating constraints that can be fixed later: - Stick to debian on beaglebone (stretch has 1.14) - Install native rust EDIT: Rust is not in Debian armhf stretch. So I need a cross compiler. Entry: Two rust applications Date: Sun Jan 21 11:14:28 EST 2018 - Thermostat control and sensor - Trusted zone for system scripts: ex. backup management Most of this is straightforward. Missing bit is an encrypted+authenticated message protocol. Entry: go via pi Date: Mon Jan 22 11:56:03 EST 2018 - Test that tftp works from pi - Create a full bridge into lab subnet - Limit access of that bridge to specific IPs Full bridge will require br0 main on pi, which is hard to set up remotely. I need something simpler. Maybe DNAT at pi level. tftp works from the pi Entry: Simplification Date: Mon Jan 22 12:46:00 EST 2018 Don't put vpn on gwtest. It works fine with dnat. The problem is elsewhere so don't complicate it. Fix it by providing an access point into the pi to end up at the lab subnet. There we have a fixed IP range. Entry: Cross compiling Date: Sat Jan 27 19:30:49 EST 2018 basic idea: - rust -> llvm - llvm -> .o - linker now i just got to read this shit... https://blog.rust-lang.org/2016/05/13/rustup.html https://hackernoon.com/compiling-rust-for-the-raspberry-pi-49fdcd7df658 Entry: impl Trait Date: Fri Mar 23 13:11:11 EDT 2018 https://www.reddit.com/r/rust/comments/86f3h6/impl_trait_stabilization_was_just_rd/ https://aturon.github.io/blog/2015/09/28/impl-trait/ I ran into this exactly with Lars: iterators getting hairy The basic idea is to allow code like the following: pub fn produce_iter_static() -> impl Iterator { (0..10u8).rev().map(|x| x * 2).skip(2) } The point here is to avoid writing a return type like iter::Skip>>> https://github.com/rust-lang/rust/issues/44721 Entry: Restore lars? Date: Fri Apr 20 22:19:47 EDT 2018 So I have a basic port skeleton for interop with Erlang. But what I really want, is expect based test driven programming. It appears I need a higher rank type. The problem is O in this definition. How to express that this works for all O? pub struct Decode<'a,I,S,T:'a,O> where for S: Iterator, T: Tick { s: S, t: &'a mut T, } Can I boil this down to some simpler example to see the core of the problem? Until then, maybe separate out the tick implementations from the iterators. /* The idea here is to take a Tick and combine it with an input stream * to produce an output stream. */ Can this be rephrased into "apply" Entry: Rust, elements Date: Sat Apr 21 16:53:00 EDT 2018 - move when possible - references when move is not possible: - read-only (fanout) - mutable refences (single) - static lifetime checking - structs and tagged unions - matching on those - closures - unboxed downward closures - traits = structs + behavior. - parameteric polymorphism Entry: lars passes tests Date: Sat Apr 21 18:59:51 EDT 2018 Getting back into it. Not sure what some of the old problems were about. Simply rephrasing them once the intention was clear seems to have worked. The other change is to have &mut references for the iterator, because the previous move semantics didn't work any more due to variable size. It's possible that adding :Sized would have fixed that, but it might make more sense to not require moves such that an iterator can be used multiple times? EDIT: This doesn't seem right. All other things like .map() will consume the iterator. Change it back? Yeah not just like that. Needs thinking. EDIT: Only last field can be dynamically sized. --> src/tick.rs:399:5 | 399 | s: Iterator, | ^^^^^^^^^^^^^^^^^^^ `std::iter::Iterator + 'static` does not have a constant size known at compile-time | = help: the trait `std::marker::Sized` is not implemented for `std::iter::Iterator + 'static` = note: only the last field of a struct may have a dynamically sized type EDIT: Still can't figure it out. Type annotation becomes hard to underastand. EDIT: Find the implementation of .map -- see below Entry: Coroutines Date: Sun Apr 22 08:41:39 EDT 2018 Since they have been so useful in my other C project. What about doing the same in Rust? Entry: Implementation of map Date: Sun Apr 22 10:49:52 EDT 2018 rust/src/libcore/iter/iterator.rs #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn map(self, f: F) -> Map where Self: Sized, F: FnMut(Self::Item) -> B, { Map{iter: self, f: f} } rust/src/libcore/iter/mod.rs #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct Map { iter: I, f: F, } #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Map { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Map") .field("iter", &self.iter) .finish() } } #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for Map where F: FnMut(I::Item) -> B { type Item = B; #[inline] fn next(&mut self) -> Option { self.iter.next().map(&mut self.f) } #[inline] fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } fn try_fold(&mut self, init: Acc, mut g: G) -> R where Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try { let f = &mut self.f; self.iter.try_fold(init, move |acc, elt| g(acc, f(elt))) } fn fold(self, init: Acc, mut g: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { let mut f = self.f; self.iter.fold(init, move |acc, elt| g(acc, f(elt))) } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for Map where F: FnMut(I::Item) -> B, { #[inline] fn next_back(&mut self) -> Option { self.iter.next_back().map(&mut self.f) } fn try_rfold(&mut self, init: Acc, mut g: G) -> R where Self: Sized, G: FnMut(Acc, Self::Item) -> R, R: Try { let f = &mut self.f; self.iter.try_rfold(init, move |acc, elt| g(acc, f(elt))) } fn rfold(self, init: Acc, mut g: G) -> Acc where G: FnMut(Acc, Self::Item) -> Acc, { let mut f = self.f; self.iter.rfold(init, move |acc, elt| g(acc, f(elt))) } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Map where F: FnMut(I::Item) -> B { fn len(&self) -> usize { self.iter.len() } fn is_empty(&self) -> bool { self.iter.is_empty() } } #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Map where F: FnMut(I::Item) -> B {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Map where I: TrustedLen, F: FnMut(I::Item) -> B {} #[doc(hidden)] unsafe impl TrustedRandomAccess for Map where I: TrustedRandomAccess, F: FnMut(I::Item) -> B, { unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { (self.f)(self.iter.get_unchecked(i)) } #[inline] fn may_have_side_effect() -> bool { true } } Entry: More about iteration Date: Sun Apr 22 10:56:59 EDT 2018 Iterator vs. All (proposal only?) https://medium.com/@veedrac/rust-is-slow-and-i-am-the-cure-32facc0fdcb FuesedIterator https://doc.rust-lang.org/beta/std/iter/trait.FusedIterator.html Entry: Is this just filter_map? Date: Sun Apr 22 11:16:59 EDT 2018 Yes. So maybe the solution is to implement FnMut for Tick? Or if that doesn't work -- seems to rely on unstable bits -- wrap it in a closure. EDIT: Yes. It was quite straightforward once I understood the next post. pub fn apply<'a,In,Out,SM,Ins> (sm: &'a mut SM, ins: Ins) -> impl 'a+Iterator where In: 'a, Out: 'a, SM: 'a+Push, Ins: 'a+Iterator { ins.filter_map(move |i| sm.push(i)) } Entry: Don't confuse traits (constraints) with trait objects (types) Date: Sun Apr 22 11:46:52 EDT 2018 Basically, in a type signature like pub fn foo The 'T' is always a type. T: Iterator What's after ':' is a type constraight such as a Trait bound, or a lifetype. (where _ is some other type, not imporant) Do not confuse this with: pub fn foo (arg: Iterator) -> { } Where what's after arg: is a type, not a type constraint. This is called a trait object. It seems there is no way to express: variable: : The constraint needs to go to where the type variable is declared. Entry: use Date: Sun Apr 22 16:11:53 EDT 2018 While types are available by paths, the behavior assocaited with them -- a trait -- only comes into scope throug a 'use' statement. Entry: where Date: Sun Apr 22 16:15:58 EDT 2018 https://doc.rust-lang.org/1.4.0/book/traits.html where is also more powerful than the simpler syntax. ... they allow bounds where the left-hand side is an arbitrary type (i32 in this case), not just a plain type parameter (like T). Entry: Rust cross compiler Date: Mon Apr 30 20:30:47 EDT 2018 This says to use the OpenWRT SDK, but I'm just using the full openwrt build. https://github.com/japaric/rust-cross https://wiki.openwrt.org/doc/howto/obtain.firmware.sdk Ok, done! No more excuses I guess. Making it small: https://lifthrasiir.github.io/rustlog/why-is-a-rust-executable-large.html Entry: OpenWRT / Buildroot Date: Tue May 1 06:28:22 EDT 2018 With that working, what's next? - Video on nexx1 - Try STM32 maybe? Entry: C FFI Date: Tue May 1 06:31:16 EDT 2018 Since I have a bunch of interface code already in C, why not focus on FFI first? Entry: STM32 Date: Thu May 10 18:45:38 EDT 2018 https://docs.rs/cortex-m-quickstart/0.2.7/cortex_m_quickstart/ Seems there is no setup fo 103, only 30x? Nope there is stm32f103xx It seems it's all there. No more excuses! Entry: Rust on STM32 blue pill Date: Sat May 19 08:51:58 EDT 2018 - UART adapter - Relay controller Main quesion: is there HAL USB support? Doesn't look like it. The low level support uses svd2rust so is likely complete, from svd. https://raw.githubusercontent.com/fduignan/stm32f103c8t6/master/STM32F103.svd Not a simple task to write USB support. And that would be a requirement, so not for now.. Entry: tock Date: Sat May 19 23:43:13 EDT 2018 https://www.cnx-software.com/2018/02/13/tock-open-source-os-for-secure-iot-systems-runs-on-arm-cortex-m-microcontrollers/ Entry: configure default=nightly for target? Date: Mon Jul 16 10:11:50 EDT 2018 I have two different setups and I don't know how this happened. Here's what I think needs to be done: - switch to nightly as default - install the other target Entry: USB firmware in rust Date: Sat Jul 28 22:53:32 EDT 2018 https://github.com/rust-lang-nursery/embedded-wg/issues/40 It does seem that building Rust code on STM32F103 boards is going to go a lot better if it is mixed with C. So focus on setting up a mixed tool chain. Entry: speeding up builds Date: Sat Aug 11 14:52:21 EDT 2018 https://vfoley.xyz/rust-compile-speed-tips/ Entry: STM32 Date: Sat Sep 15 13:01:19 EDT 2018 See https://github.com/rust-embedded/cortex-m-quickstart EDIT: Compiling a trival busy loop, I get this: [ 1] .vector_table PROGBITS 08000000 001000 000400 00 A 0 0 4 [ 2] .text PROGBITS 08000400 001400 0028e8 00 AX 0 0 4 [ 3] .rodata PROGBITS 08002d00 003d00 0018e0 00 AM 0 0 32 [ 4] .data NOBITS 20000000 006000 000000 00 A 0 0 4 [ 5] .bss NOBITS 20000000 006000 000000 00 WA 0 0 4 Which is around 16K overhead. More than I expected, but not too bad. Likely most of this is the error printing. Next: load it. Alright. tom@tp:/i/tom/uc_tools/rust$ arm-eabi-gdb-7.6 GNU gdb (GDB) 7.6 ... (gdb) target remote localhost:3333 Remote debugging using localhost:3333 0x00000000 in ?? () (gdb) file bluepill.elf A program is being debugged already. Are you sure you want to change the file? (y or n) y Reading symbols from /net/10.1.3.2/panda/home/tom/pub/git/uc_tools/rust/target/thumbv7m-none-eabi/release/bluepill...done. (gdb) load Loading section .vector_table, size 0x400 lma 0x8000000 Loading section .text, size 0x28e8 lma 0x8000400 Loading section .rodata, size 0x18e0 lma 0x8002d00 Start address 0x8000880, load size 17864 Transfer rate: 15 KB/sec, 5954 bytes/write. (gdb) c Continuing. Program received signal SIGTRAP, Trace/breakpoint trap. 0x08002c6c in __bkpt () etc... So looks like this works. Next: make it do something. Blink a LED, maybe run under bootloader? Entry: Different rust compilers Date: Sat Sep 15 13:27:26 EDT 2018 But I don't want a "current" one. E.g. I need this configured per project, not globally. How? EDIT: per directory settings rustup override set nightly-2016-09-17 rustup override --help Entry: Propagate Result in an iterator? Date: Tue Sep 18 18:25:46 EDT 2018 https://stackoverflow.com/questions/36368843/whats-the-most-idiomatic-way-of-working-with-an-iterator-of-results EDIT: The solution is to use for loops instead of higher order functions. Entry: Initializing arrays Date: Wed Sep 19 19:43:12 EDT 2018 An alternative to unsafe. - reserved: unsafe { mem::zeroed() } + reserved: array_init::array_init(|_| 0) https://docs.rs/crate/array-init/0.0.4 Entry: Serde Date: Wed Sep 19 19:56:51 EDT 2018 https://github.com/serde-rs/serde Entry: Rust on STM Date: Wed Sep 19 21:42:17 EDT 2018 So basically, I was able to load the code. Next: I need some target application to drive this. What would this be? Maybe create a relay interface board with a decent command line interface. Entry: How to send strings through channels? Date: Mon Jan 7 12:04:44 CET 2019 EDIT: See app code. Entry: USB STM32 Date: Mon Feb 11 13:05:39 EST 2019 https://github.com/rust-embedded/wg/issues/40 This issue is for gathering resources on writing USB firmware in Rust and for tracking progress on building a generic USB stack in Rust. Entry: Rust without allocation Date: Sun Feb 24 07:50:11 EST 2019 Basically, how to do more with the stack. I have this mmap thing. How to create slices that do not copy? The idea is to use iterators and references. How to create a slice? Entry: Moving an Option, replacing origin with None Date: Mon Mar 4 08:24:37 EST 2019 https://doc.rust-lang.org/std/option/enum.Option.html take Entry: Composing iterators Date: Tue Mar 5 08:18:38 EST 2019 This is something I ran into last time, which I believe is fixed now: the ability to specify return types more generally. Entry: Itertools Date: Tue Mar 5 09:10:55 EST 2019 So I run into the error: error[E0599]: no method named `interleave` found for type `tools::GapRangeIterator<'_, T>` in the current scope According to doc this is implemented here: https://docs.rs/itertools/0.6.0/itertools/trait.Itertools.html#method.interleave Trait itertools::Itertools So how do I add this trait? This seems to be a basic pattern: a trait is provided in a library. How to "inherit" from it? Entry: Iterators and Specs Date: Tue Mar 5 09:32:45 EST 2019 When a separate wrapper IntoIterator object is necessary, make sure that the Iterator that is generated does not include a reference to the wrapper spec. In practice it appears to be hard to keep that wrapper around long enough on the stack, so either move/copy it into the Iterator, or just copy over fields that are necessary. The more general context is that it is necessary to have both these traits: - Iterator: iteration state consumed during iteration - IntoIterator: container object that can pruduce many Iterator Typically, more general objects can be wrapped in a struct with the sole purpose of implementing IntoIterator. This wrapper is often temporary, so don't include a reference to this wrapper in the Iterator instance. Copy over data, or copy/move the wrapper in its entirety. Entry: unwrap ? Date: Sat Mar 9 11:35:32 EST 2019 Sometimes a little convoluted.. use .as_ref() .map and ? let ts = slice[i_first].as_ref().map(|s| s.timestamp())?; EDIT: See next post Entry: Indices, borrow schecker and 2-phase scan,update Date: Sun Mar 10 08:00:15 EDT 2019 Often it makes sense to replace the use of mutable references with index + immutable reference. Then, outside of the immutable borrow context, the index can be used to perform a mutation. Splitting up the algorithm in: - gather information, and - perform update Also makes it easy to see what is actually being changed. Basically, inspections can never hurt anyone, only changes can. If the data returned by the scan phase is encoded properly so a lot of weight is bore by the type of the update data structure, the update can usually be performed in a way that clearly satisfies all invariants. Example: a fat reference into &[Option] could contain the information that at a certain index:I there is actually a Some, so the fat index could be could be I + T instead of I + Some. Entry: destructing dynamically typed data Date: Sun Mar 10 09:22:12 EDT 2019 Doing the Erlang->Rust bridge, I am reminded about how tedious it is to write ad-hoc destructuring. For my use case (eetf), this seems to work: - Use accessors and short-circuiting '?' instead of pattern matching. This allows simpler expression of all the constraints that need to be met for the dynamic type to be accepted. There is too much "unused space" in the dynamic type to use all-clause matching. - In Rust, this means map.collect is awkward to use. It's simpler to create conversion functions that use early exit and explicit vec.push This does point at the problem though: is there a short-circuiting .collect() ? There is .fold_option() However, it seems simplest to just create separate destructor functions that wrap the result in Option. Is there a simpler way? Map a symbol to a constructor? It appears the conversion needs to be expressed somewhere, and it is bound to be ad-hoc because of the difference between the two worlds. So let's not worry. Entry: Rust on uC Date: Sun Mar 10 14:44:44 EDT 2019 I want to first do this as an .o that can be linked into an existing C project. It seems it will create an .a, wich is fine: https://doc.rust-lang.org/reference/linkage.html --crate-type=staticlib, #[crate_type = "staticlib"] - A static system library will be produced. This is different from other library outputs in that the compiler will never attempt to link to staticlib outputs. The purpose of this output type is to create a static library containing all of the local crate's code along with all upstream dependencies. The static library is actually a *.a archive on linux and osx and a *.lib file on windows. This format is recommended for use in situations such as linking Rust code into an existing non-Rust application because it will not have dynamic dependencies on other Rust code. Entry: specyfing return value traits Date: Thu Mar 14 12:27:57 EDT 2019 This is impl Trait: https://doc.rust-lang.org/edition-guide/rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.html For reference: look at how the JackClient trait is handled in the looper project. Two things are important: - client.activate_async from the jack library returns a type that is parameterized by a closure, so we can't even specify it explicitly. - the solution i've found is to put it in a struct that is parameterized by this type. struct SimpleJackClient

{ async_client: jack::AsyncClient<(), P> } - then create a trait that is implemented with P constrained: impl

JackClient for SimpleJackClient

where P:jack::ProcessHandler { } - this trait can be reused for other things, but for now the only important property is that it is implemented for the SimpleJackClient for any return value of client.activate_sync - my main constructor returns "impl JackClient". this means it can still be inlined into another struct. i.e. I'm not yet limiting that possibility yet. - however, it ends up being stored in some object store as a Box which is a trait object. Conclusion: I did some extra wrapping because I need it anyway, but there are 3 things to distinguis: - impl Trait will be a concrete type known at compile time - Box is such a concrete type inside a box, exposing only the interface - &Trat is similar, but just an abstract reference to a concrete type Entry: STM32 Date: Sat Mar 14 16:52:35 EDT 2020 Prob going to stick to C for blue pill work for now, but I do have a bunch of discovery boards. See list here. https://docs.rs/releases/search?query=stm32f4 Supported: https://docs.rs/crate/stm32f407g-disc/0.4.0 https://docs.rs/stm32f072b-disco/0.2.1/stm32f072b_disco/ Entry: Embedded Rust Book Date: Sat Mar 14 17:08:49 EDT 2020 https://rust-embedded.github.io/book/ Following install instructions. serde doesn't compile. Always fucking build problems with these large projects.. tom@panda:~/constell8/doc$ rustc --version rustc 1.34.0-nightly (3315728c0 2019-02-09) I guess I need to upgrade. Will that cascade? Too much work atm. Entry: Prepare rust embedded Date: Wed Mar 18 10:20:36 EDT 2020 Get it to work on at least one board. I think I already had it compiling for the f103. EDIT: Ok I have blinky. Trying f4 also, and I really don't feel up to digging into the API without something specific to look for. But it sort of works. Entry: oxidize Date: Fri Mar 20 13:39:25 EDT 2020 Generic follow-up: - https://github.com//rust-embedded/wg I'm going to trust that these chatrooms do not disappear, so here are just some basic notes from each talk: * Tony Arcieri - Armistice: Embedded Rust Cryptographic Application Environment https://riot.im/app/#/room/#ox1k-tony-arcieri-armistice:chat.berline.rs * Kornel - C is Dynamically Typed https://riot.im/app/#/room/#ox1k-kornel-c-dynamically-typed:chat.berline.rs * Frank A Stevenson - Concurrent Event Handling in a Single Thread Using .await https://riot.im/app/#/room/#ox1k-frank-stevenson-concurrent-event:chat.berline.rs - embrio: https://github.com/Nemo157/embrio-rs - experiments with integrating RTFM and async - frozendroid: We're also considering using the work that the polymer-kb guys have done with embrio for our project frank_a_stevenson: I have not found any issies with polymer-kb and embrio , but they are kind of obscure crates and expect to have to fix any issue that I find with them myself. - jschievink: I hope the async-on-embedded advances we've made will help with this sort of stuff - cybertreiber: fascinating how concise this multiplexing can be expressed. one thing i didn't get was if/how more than one async fn could await on csac events? - darkwater: on a regular executor (with std and an OS) you can do something like tokio::spawn(some_task) to spawn a parallel task. I assume you can also do this on embedded eventually, but for now on embrio you can do something like a join/select - darkwater: async/await is really (mostly) just syntax sugar for futures, and you can poll multiple futures in succession - zwizwa: Has anyone tried combining async with other schedulers, like a CSP scheduler or something like "redo" or "make"? jschievink: there's some experiments with integrating RTFM with it - zwizwa (on embrio) This looks awesome. Do you have any writeups? darkwater: I don't, but it looks like Ferrous is working on a proper system.. embrio looks to be more of an experiment without much proper documentation https://ferrous-systems.com/blog/async-on-embedded/ skade: I wouldn't got as far as that embrio is only an experiment, but it always made all sorts of hacks to simulate the future * Nicolas Stalder - Cryptography on Cortex-M4: Rust + Assembly = Love https://riot.im/app/#/room/#ox1k-nicolas-stalder-cryptography-cortex-m4:chat.berline.rs * Vadim Kaushan - Do You Really Need to Run Your Firmware on the Device? https://riot.im/app/#/room/#ox1k-vadim-kaushan-firmware:chat.berline.rs - wolfwood: so awesome. tunnel all the memory access to the mcu, run everything else in emulation on the pc ( this is close to what I've been thinking about with the CSP, turning all interrupts into messages ) * Jonathan ‘theJPster’ Pallant - How We Got QUIC Running on the nRF9160 Before Everyone Else https://riot.im/app/#/room/#ox1k-jonathan-pallant-quic:chat.berline.rs * Mrinal Wadhwa - IoT Needs Secure Messaging and How Rust Can Help https://riot.im/app/#/room/#ox1k-mrinal-wadhwa-iot-needs-secure-messaging:chat.berline.rs - ockam-community.slack.com - things are super early, but here are few links https://github.com/ockam-network/ockam - main codebase https://github.com/ockam-network/proposals - design proposals, the issues in this repo have some discussion as well http://ockam.io/learn * Conor Patrick - Making an Embedded Rust NFC Application from Scratch https://riot.im/app/#/room/#ox1k-conor-patrick-embedded-rust-nfc:chat.berline.rs * Bryan Cantrill - Tockilator: Deducing Tock Execution Flow from Verilator Traces https://riot.im/app/#/room/#ox1k-bryan-cantrill-tockilator:chat.berline.rs - jschievink: yeah the rust crates for ELF/Object Files/DWARF are really good - Daniel Näslund: Yeah, there should be more simulators - everywhere. It's like some have given up on simulators and say: Hey we have our J-Link trace probes. We can just load the code to our boards and explore the code from there. But a simulator has so many advantages. - Daniel Näslund: bcantrill: And writing simulators is so fun. :) There are 3 things people can't keep their hands from doing: their own language; writing simulators and doing crypto. * Robert Jördens - Ruling Quantum Technologies with Embedded Rust https://riot.im/app/#/room/#ox1k-robert-joerdens-quantum-embedded:chat.berline.rs - frank_a_stevenson: You said you are using softcore CPU, have you looked at hybrid FPGA solutions ? Why would you want to use a softcore? - tom->frank_a_stevenson: ah as far as i know the IO from hardcores is very restricted and often surprisingly slow. Piping a control process through a AXI port has non-trivial overhead? * Dominik Boehi - probe-rs - Improving the Embedded Debug Experience https://riot.im/app/#/room/#ox1k-dominik-boehi-probe-rs:chat.berline.rs - slides of tiwaluns talk: https://tiwalun.github.io/oxidize-1k-probe-rs/#/ - webpage: https://probe.rs - matrix channel: https://matrix.to/#/!vhKMWjizPZBgKeknOo:matrix.org - repository: https://github.com/probe-rs/probe-rs/ - cargo-flash repository: https://github.com/probe-rs/cargo-flash/ - vscode plugin repository: https://github.com/probe-rs/vscode/ Entry: Tock Date: Sat Mar 21 21:00:53 EDT 2020 https://www.youtube.com/watch?v=Q6QwH8tSDkA&t=1114s two hals: - EWG (embedded workgroup, focus on HAL, svd2rust) - Tock (has its own HAL) Entry: Oxidize 1k: videos Date: Mon Mar 30 15:50:49 EDT 2020 https://www.youtube.com/watch?v=zPuELAzJyno Reviewing: * Frank A Stevenson - Concurrent Event Handling in a Single Thread Using .await https://riot.im/app/#/room/#ox1k-frank-stevenson-concurrent-event:chat.berline.rs Core idea seems to be 1) use cooperative multitasking with meaningful (transactional) suspend points instead of pre-emptive multitasking 2) instead of doing that (as is done typically) with explicit state machines, let rust generate the state machines using the async framework. Contacted on LikedIn. I'd like to get a discussion going. Entry: How to switch rust compilers? Date: Wed Apr 1 20:19:04 EDT 2020 I was using this: tom@panda:/nix/exo$ rustc --version rustc 1.34.0-nightly (3315728c0 2019-02-09) But that breaks: pip install --user cmsis_pack_manager So I did rustup update stable rustup default stable So how do you use a specific toolchain in a project? Entry: code bloat: one superbinary Date: Mon Apr 13 20:29:43 EDT 2020 https://www.youtube.com/watch?v=EoV94cg_Tug around 20:00 put code in .so you you can still dlopen. @24:07 Zephyr rust https://github.com/tylerwhall/zephyr-rust Entry: async-std Date: Tue Apr 14 23:06:40 EDT 2020 https://www.youtube.com/watch?v=L7X0vpAU-sU so... This is a runtime. If you write libraries, don't use a runtime but use futures directly. There are other runtimes: - async-std - tokio - fuchsia - bastion (reliability) - wasm-bindgen-futures https://www.youtube.com/watch?v=skos4B5x7qE - futures (pollables) - executor (schedules polling, hands over to reactor on io) - reactor (waits on i/o to hand over to executor) Core issue in initial design was due to self-referential structures, which cannot be moved. Solved by requiring that futures cannot be moved, i.e. "pinned". Entry: rust async lecture Date: Fri Apr 17 23:02:29 EDT 2020 https://www.youtube.com/watch?v=9_3krAQtD2k - when not ready, future/task must register to be woken up again (task) - create task for each future - main event handler (io reactor?) is given task handle well i get the general idea, but details are not really clear basically a future is the thing that is being polled, but it is run inside a task, which knows about the executor. seems convoluted. why are these separate? the reactor is part of implementation (tokio) cont watching... implementing futures will necessarily depend on the "reactor" part. using futures, it can be abstract. Entry: Version bumping rust Date: Sat Apr 18 13:38:54 EDT 2020 warning: trait objects without an explicit `dyn` are deprecated Entry: Async embedded Date: Mon Apr 20 18:23:34 EDT 2020 How to get started on aligning ideas with Frank? Maybe start by asking questions. EDIT: Also asked on irc (why don't you try it) and ran into ferrous systems stuff: tom@panda:~/git/async-on-embedded$ git log |grep Author Author: Florian Gilcher Author: Martin Kröning Author: Jorge Aparicio Author: Vadim Kaushan The first question I have is why am I seeing mutexes? That is a smell. Async should be free of shit like that so where does it come from? 19:06 < doelie> Hi. If I want to get into no_std async, what should I try first? embrio? anything else? 19:08 < doelie> or https://github.com/ferrous-systems/async-on-embedded ? 19:09 < doelie> It's just for expirmentation now, but I want to pick something that will evolve into something stable in the future. 19:19 < doelie> I guess the subtext is: is it dumb to start writing my own special purpose executor? 19:19 < agg> i think at this stage you might as well go for it! 19:20 < agg> if nothing else it will probably be interesting and might put you in a good position to help guide future work too 19:20 < agg> I don't think there's currently a clear or obvious choice for it on embedded, or at least not that I know of 19:26 < doelie> that's all the encouragement i needed :) 19:47 -!- pzzy [~pqzx@unaffiliated/pqzx] has quit [Quit: Leaving] 19:58 < doelie> I can see some room for diversity. I see ferrous sees a need for Mutex in the generic case, while I usually have the inclination to not use those but use monitor processes to manage shared resources, which might be too simplistic for the general case. 20:10 < doelie> But it does seem that writing something that pleases everyone is going to take a while... 20:10 < doelie> So a recipe for how to keep it simple in special cases might not be so bad. Entry: Deriving From Date: Sun Apr 26 12:31:35 EDT 2020 #[derive(From)] enum AppError { AppVarError(std::env::VarError), AppParseIntError(std::num::ParseIntError) } error: cannot find derive macro `From` in this scope EDIT: This was just another crate [dependencies] derive_more = "0.9" extern crate derive_more; use derive_more::From; Entry: Publishing lars Date: Tue Apr 28 17:58:17 EDT 2020 The name is already used, so pick a new name larsalyzer logan Entry: confused again Date: Wed Apr 29 17:15:38 EDT 2020 package crate library module As I understand it, a crate can export a [lib] which will be the name of the crate, but that's not the same as the name of the package. https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html - crate is a library or a binary - a package is a collection of crates - crates.io contains packages - Cargo.toml refers to packages A lot fo the confusion comes from a package containing 0 or 1 libraires, so in most cases package and library can be glossed over as being the same. But they are not. And they can have different names. I guess this is useful for making drop-in replacements. Entry: Writing music state machines in Rust async Date: Thu Apr 30 11:23:39 EDT 2020 If you write generative music, it tends to be easy to do this in a linear style, but that then leads to an explosion of processes. It would be great to see what Rust async can do here. Also, block-based algorithms might benefit from not being written in raw state machine style, but as a linear async process. EDIT: So I wonder if what I am looking for is actually a generator, because the futures do not seem to produce any intermediate values. EDIT: It probably doesn't matter. Async will probably work fine with some idea of input/output ports. I need an example: an envelope. So basically what I want is an async function that "blocks" on reading its inputs, and can update its outputs. Then the scheduler is essentially "redo". Entry: Wait for generators/coroutines? Date: Sun May 3 08:29:19 EDT 2020 Maybe best to first understand it properly. Generators follow this flow: - caller starts G with a value - G recevies that as a start argument - G can yield or return a value - caller of start receives Yielded/Complete value - calller can resume G with a value Now what is the difference? Async is 1. value-oriented and 2. compositional, e.g an async function can call other async functions. Coroutines / generators are a different concept. Async functions still make sense in combination with channels, because read and write are blocking operations. So I probably should aim for that first. TODO: 1. set up some system that uses channels + async 2. evaluate this (i.e. look for "select") Entry: rust libopencm3 Date: Tue Jun 2 00:19:14 EDT 2020 https://docs.rs/libopencm3_sys/0.0.2/libopencm3_sys/index.html Entry: gui Date: Sun Jun 7 10:06:34 EDT 2020 https://users.rust-lang.org/t/current-state-of-gui-development-in-rust/11643 Entry: Minimal .a to include in C file Date: Thu Jul 2 21:20:27 EDT 2020 rustc --crate-type=staticlib -C panic=abort src/lib.rs #[no_mangle] pub extern fn add1(i:u32) -> u32 { i+1 } Still why is there a mention of panicking? 00000000000007c0 : 7c0: 50 push %rax 7c1: 83 c7 01 add $0x1,%edi 7c4: 0f 92 c0 setb %al 7c7: a8 01 test $0x1,%al 7c9: 89 7c 24 04 mov %edi,0x4(%rsp) 7cd: 75 06 jne 7d5 7cf: 8b 44 24 04 mov 0x4(%rsp),%eax 7d3: 59 pop %rcx 7d4: c3 retq 7d5: 48 8d 3d 64 01 00 00 lea 0x164(%rip),%rdi # 940 7dc: 48 8d 15 c5 05 20 00 lea 0x2005c5(%rip),%rdx # 200da8 <__JCR_END__+0x8> 7e3: 48 8d 05 36 00 00 00 lea 0x36(%rip),%rax # 820 <_ZN4core9panicking5panic17hcdc9f0ba8d71d265E> 7ea: be 1c 00 00 00 mov $0x1c,%esi 7ef: ff d0 callq *%rax 7f1: 0f 0b ud2 7f3: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 7fa: 00 00 00 7fd: 0f 1f 00 nopl (%rax) My guess is that this is always added to every function, as unwinding is done one function at a time? Is there a way to disable this? -O gets rid of it: rustc --crate-type=staticlib -C panic=abort -O add1.rs gcc test.c -L . -ladd1 -Wl,--gc-sections Entry: How to create a no_std library? Date: Thu Jul 2 22:38:24 EDT 2020 I guess it's just adding #![no_std] to the toplevel .rs file.