r/learnrust

I have some C knowledge including dynamic memory allocation (but not file io) am i qualified enough to learn rust as my second language?

basically the title, plus I also know about some common C pitfalls

reddit.com
u/YOYOBunnySinger4 — 1 hour ago
▲ 0 r/learnrust+1 crossposts

Linux updates shouldn't be scary. for new users

So I built ButterUp 🧈

✅ One-click updates
✅ Auto-fixes common update issues
✅ Cleans old system junk
✅ Update history

Rust + Tauri • Open Source

Try it: https://lnkd.in/dVxGKceP
linkedin post : https://www.linkedin.com/posts/abdulfarhath_linux-opensource-buildinpublic-activity-7478485753719709697-pY5s

https://preview.redd.it/jtfpu1ukmzah1.jpg?width=933&format=pjpg&auto=webp&s=fe4d1a3e7d280d49474dfe4ba17582d845481fc2

reddit.com
u/YouthAccomplished690 — 3 days ago
▲ 56 r/learnrust+1 crossposts

Wonderd about a Shell in Rust

So I had made a shell using rust about this it started initially as a codecrafters challenge but made some tweaks and customisation and added some extra feature it's one of my first biggest project made in rust took about 3 weeks to complete it has some limitations obviously as I am not a geniuses but would love to take some reviews about this project you can see it's code and it's features from here

https://github.com/Halloloid/hallo\_shell

And forgot the name of the shell is halloShell the name is originated from my GitHub username

u/CompleteNetwork9168 — 3 days ago
▲ 131 r/learnrust+1 crossposts

tokio for I/O, rayon for CPU: how we bridge them in a Rust search engine

Disclosure: I work on infino, an Apache-2.0 embedded retrieval engine in Rust. This is an internals post about how we split work between tokio and rayon, and a couple of spots where we got it wrong before benchmarks caught it.

Quick context: infino stores data in superfiles, standard Parquet files with a BM25 index and a vector index embedded just before the footer, so they stay fully readable by any normal Parquet reader (more details in the storage-format post). A supertable is a manifest referencing many append-only, snapshot-isolated superfiles.

A query against a supertable opens up some of those superfiles from object storage. That work splits into two different jobs. Opening the files, sending GET ranges to S3, Azure, or disk, and prefetching tombstone sidecars is I/O: awaitable, and none of it CPU heavy. Decoding the Parquet pages, scoring BM25 postings, computing vector distances, and reranking is CPU work: synchronous, and wanting a core to itself for a few milliseconds at a time.

Put both the above tasks on one tokio runtime and you have a problem: tokio's scheduler only yields at .await points, so a CPU-bound task blocks everything else on that worker thread until it finishes. spawn_blocking gets you out of that, but it hands out one OS thread per task, not the fixed-size, work-stealing pool you actually want for chunked parallel compute. To resolve this problem, our approach uses both tokio and rayon: tokio owns I/O, rayon owns CPU.

Query fan-out is one tokio::spawn per superfile on a shared multi-thread runtime, joined with try_join_all (supertable/query/dispatch.rs):

let handles = units.into_iter().map(|(entry, params)| {
    let store = Arc::clone(&store);
    let handle = tokio::spawn(async move {
        let r = open_reader(&store, disk_cache.as_ref(), storage.as_ref(), &entry).await?;
        body(r, entry, tombstone_cache, now, params).await
    });
    async move { handle.await.map_err(|e| QueryError::Store(format!("fan-out task join: {e}")))? }
});
try_join_all(handles).await

CPU work runs on a pair of rayon pools sized to the machine, one for reads and one for writes, built once and shared by every open Supertable in the process rather than per-handle or falling back to rayon's global pool (supertable/options.rs):

fn default_reader_thread_count() -> usize {
    num_cpus::get().max(1)
}

static SHARED_READER_POOL: OnceLock<Arc<ThreadPool>> = OnceLock::new();

fn shared_reader_pool() -> Arc<ThreadPool> {
    Arc::clone(SHARED_READER_POOL.get_or_init(|| {
        Arc::new(
            ThreadPoolBuilder::new()
                .num_threads(default_reader_thread_count())
                .thread_name(|i| format!("supertable-reader-{i}"))
                .build()
                .expect("invariant: rayon pool build only fails on thread-spawn failure"),
        )
    }))
}

pool.install(|| ... .par_iter() ...) runs shard builds and warm-read Parquet decode on it (supertbale/build.rs, query/exec/common.rs).

Bridging the two with a oneshot channel

The tricky part is the seam between them. An async task that needs CPU work can't call par_iter() inline, because that blocks the tokio worker until it's done and stalls every other task on it. So instead we hand the closure to rayon and await a tokio::sync::oneshot for the result. Here's the coarse-to-fine vector scoring path doing exactly that (superfile/vector/reader.rs):

let (tx, rx) = oneshot::channel();
rayon::spawn(move || {
    let acc = meta_owned
        .par_chunks(chunk)
        .zip(blocks_owned.par_chunks(chunk))
        .map(|(meta_chunk, block_chunk)| score_cluster_codes_into_heap(meta_chunk, block_chunk))
        .reduce(/* ... */);
    let _ = tx.send(acc);
});
let acc = rx.await?;

The tokio worker is free to poll other tasks while rayon does the scoring. The rule: no single thread should ever be both an async-runtime driver and a rayon worker at the same time. Other search engines like Meilisearch have hit exactly this bug in production; their writeup is worth a read (linked below).

Sync code calling back into async

That bridge only goes one way. Infino also needs the reverse: the public API is sync (Supertable::append, bm25_search, vector_search), but the storage layer underneath is async (object_store is an async trait). Calls from rayon threads, the CLI, and the Python bindings all need to drop into async code to do I/O, then hand back a plain value.

runtime_bridge.rs handles this. If there's already a multi_thread runtime running, it uses block_in_place + Handle::block_on. For the rayon-thread case, where there's no ambient runtime, it builds a current_thread runtime and drives the future on that instead.

We got this wrong at first. An earlier version of the code routed every sync caller through one shared multi_thread().worker_threads(1) runtime instead of a current_thread one, on the theory that reusing a runtime beats building one per call. That part's true, but a multi_thread runtime's block_on adds per-poll coordination with its worker thread that current_thread doesn't pay, since it just polls inline with no handoff. The commit that fixed it recorded the cost: +6-17% on multi-term FTS search at 10M docs, worse the more async fan-out a query did; single-term queries were unaffected. Switching back to current_thread fixed it.

Which runtime flavor you pick for this bridge matters as much as which pool you pick for the other one, and it wasn't obvious which one would win until we measured it.

A second tokio runtime instead of rayon

While researching this I ran into Andrew Lamb's (InfluxDB IOx / DataFusion) case for the opposite bridge: a second, dedicated tokio runtime for CPU work, instead of rayon. The point here is that rayon has no idea it's part of an async system, since it has no cancellation and no yielding, while a second tokio runtime is at least built the same way as the first one. This work is still pushing this upstream (tokio#8085, a proposed spawn_compute API).

We haven't hit the problems that argument is solving for. Our compute bursts are short and we don't need to cancel them mid-flight, unlike DataFusion's long-running operators. However, this might be an area of exploration for us in the future.

Where to read the code

Two things that would be interesting to get this sub's take on as we continue exploring:

  1. Rayon+oneshot versus a second tokio runtime for CPU work. For short bursts like ours, does the second runtime's cancellation support actually matter, or is it solving a problem we don't have?
  2. We used to build a reader pool, a writer pool, and a query runtime per Supertable, and it kept one table's queries from starving another's, until you open more than a couple tables and now it's N pools elbowing each other for the same cores. So we merged all three into process-wide singletons. Fixes the oversubscription, but a busy table can now crowd out a quiet one, since there's no isolation between them anymore. Anyone actually solved fair-share on a shared rayon pool? Rayon has no notion of priority itself, so my guess is whatever works has to live above the pool, not inside it. Curious if that's right.

References:

(Disclosure again: infino is Apache-2.0 OSS, and there's a commercial hosted version coming. This post is about the engineering, specifically about the use of tokio and rayon in the core engine.)

u/gilfyole — 4 days ago
▲ 7 r/learnrust+2 crossposts

Monocoque new release 0.1.7: my pure-Rust async ZeroMQ runtime runs on tokio now, not just io_uring

Context: Monocoque is a pure-Rust ZeroMQ-compatible runtime (ZMTP 3.1), no libzmq, no C dependency. I have not posted since 0.1.3, so this covers 0.1.4 through 0.1.7. Numbers are on an i7-1355U (12 threads), Linux 6.17, rustc 1.96, loopback TCP, sender and receiver on separate OS threads, unless noted.

The headline is the backend split in 0.1.6. It runs on either io_uring or tokio now, chosen by a Cargo feature: runtime-compio (default, native io_uring) or runtime-tokio (the same socket stack on tokio, for macOS, Windows, older kernels, or to drop into an existing tokio program). They are mutually exclusive. Adding tokio was additive because the protocol stack is already generic over the io traits, so one small runtime facade names the concrete runtime and a thin tokio stream adapter implements the same owned-buffer io traits with no extra copy on the data path. No protocol code changed, and both backends keep sockets !Send.

PUSH/PULL throughput with coalescing on, per backend against rust-zmq:

msg compio (io_uring) tokio (epoll) rust-zmq
64 B 9.2M 13.6M 1.33M
256 B 5.6M 9.8M 1.09M
1 KB 2.4M 5.3M 656K
4 KB 841K 1.74M 328K
16 KB 268K 473K 117K

On these single-flow loopback microbenchmarks tokio/epoll is the faster of the two. io_uring's edge is on real network I/O and high connection counts, not loopback ping-pong, which is why compio stays the default. Both beat rust-zmq once coalescing batches the writes, but coalescing is opt-in and you flush() when you want the bytes out, so it is a throughput mode, not the default.

0.1.4 and 0.1.5 cut per-message cost in a few places. Large PUSH frames now go out with a vectored write (writev via compio's write_vectored_all) instead of copying each body into the userspace send buffer: above SocketOptions::vectored_write_threshold in eager mode, the header and the refcounted Bytes body go to the kernel as an iovec, and the header buffer and iovec list are reused so the path allocates nothing. The default threshold is 32 KB, the measured loopback crossover, where skipping the copy starts to win by about 1.1 to 1.3x on the machine I tested for it (a 4-core cloud Xeon, not the i7 above). The worker-pool PubSocket coalesces a burst of queued broadcasts into one per-subscriber vectored write while keeping the fan-out zero-copy through shared Bytes clones. On the receive side, recv_batch blocks for one message then drains every further message already decoded from the same kernel read, and recv_into writes frames into a caller-owned buffer you reuse, so a steady loop does no per-message allocation. recv_into takes 64 B from about 7.7M to 9.7M msg/s, tapering as messages grow and the path turns bandwidth-bound.

0.1.5 also added worker-pool pipelines. A plain PUSH or PULL owns one connection, so it cannot drive a pool. PushFanOut binds once, accepts N PULL workers, and round-robins sends across them, which is the ZMQ load-balancing rule. PullFanIn merges N PUSH workers into one fair-queued stream with a batched handoff, one channel hop and one await per kernel-read batch instead of per message. That roughly doubles small-message sink throughput, from about 5.25M to 9.9M msg/s at 64 B on the reference machine.

0.1.7 is correctness work. PullFanIn had a memory bug: the merge channel bounded the number of queued batches, but each batch was a whole kernel read of unbounded message count, and a frozen message pins its whole 64 KiB slab page, so a sink that fell behind its readers held a growing set of pages. Peak RSS reached about 66 MB at 32 workers and 64 B, roughly ten times a single PullSocket at the same rate. Readers now forward each read in fixed-size chunks with the channel capacity lowered to match, so queued messages and their pinned pages are bounded regardless of payload or worker count, and RSS at that cell drops to about 15 MB with throughput unchanged. Separately, TCP_NODELAY was set at connect but skipped on three socket-creation paths, automatic reconnection, XPUB accepting a subscriber, and XSUB connecting upstream, so a reconnected socket ran with Nagle's algorithm on until the process restarted, quietly raising latency on the sockets you would pick for low latency. All three now apply the same setsockopt as the initial connect. Both fixes ship with regression guards: a peak-RSS bound on PullFanIn and fd-level checks that read TCP_NODELAY off the live socket, each confirmed to fail with its fix reverted. 0.1.4 also migrated the workspace to Rust edition 2024.

Repo, full changelog, per-backend tables and IPC numbers: https://github.com/vorjdux/monocoque

Run it and tell me where it doesn't hold up.

u/vorjdux — 3 days ago

How do I learn backend + Rust?

Rust is my first language, and I want to learn CLI, TUI, and backend development, although right now backend is my priority.

I've already become quite familiar with Rust's syntax, at least I think so. According to the Rustlings exercises, I've completed all of them up to lifetimes, which is the topic I'm currently working on.

And by consulting AI, I've learned a bit more (itarators, closures, and tests), but I'm stuck: creating projects. I suppose I understand the syntax, but I don't know how to start a project (even one that's not backend-related). So, I'm wondering, how do you learn backend logic + Rust? Or do you just research backend concepts separately and try to integrate them into Rust?

I found the book "Zero to Production Rust." I don't know if it's up-to-date, but I understand it uses Actix. I'd like to learn Axum, though, and I'd still look into it. What do you think?

How do you guys do it?

reddit.com
u/AugieBit — 3 days ago
▲ 82 r/learnrust+1 crossposts

Learning Rust before C, is this a bad idea?

I'm a 6th-grader who likes coding and lately, I've found myself relying way too much on AI for it, and so I decided to learn a new programming language.

I am already familiar with Python, but I am far from good. My best program was literally just a [yaml shopping list thingie](http://github.com/ItzOratotITA/hyperlister) that only worked when run in its own directory.

First option was JS, since it does play a main role in web dev, and I have a [website](http://www.oratot.com) where I host existing utilities but most of the javascript is AI generated.

But C seemed way too essential. So I tried learning it using ChatGPT's Study and Learn thingie (it was basically my only option). It got confusing very very quickly. And I guess that's the point, C is like the first layer of abstraction after machine code/asm.

Everywhere I went I heard that I should learn C before Rust, but Rust was really really appealing because it is really future proof and had all the C++ features like classes, except it was not a mess, but most importantly there are A LOT of Rust projects (like PommeMC or Paru) that I would really like to contribute to once I reach a certain level of skill. So I tried it.

Both the C stuff and the Rust stuff happened in 1 day (yesterday) and I liked Rust a lot. Basically, my equivalent to hello world when learning a programming language is making a [silly little quiz](http://github.com/ItzOratotITA/quiz), so I have to learn how to do if statements, loops, etc. and that's where C got confusing.

Is the code I wrote there good?

Should I learn another language instead of Rust?

Should I just learn C anyways?

What's a good way to learn Rust?

u/Which-Taro5092 — 5 days ago

My try on The Book's 4.3 programming problem

The problem was:

Write a function that takes a string of words separated by spaces and returns the first word it finds in that string. If the function doesn’t find a space in the string, the whole string must be one word, so the entire string should be returned.

My try was:

fn main() {
    let string1 = String::from("testing");
    let string2 = String::from("This is a test");

    thingy(&string1);
    thingy(&string2)
}

fn thingy(s: &String) {
    for (i, c) in s.chars().enumerate() {
        let len = s.len() - 1;

        if c == ' ' {
            println!("{}", &s[0..i]);
            break;
        }

        if i == len {
            println!("{s}");
            break;
        }
    }
}

From what I've tried, it works well... I am now looking at The Book's solution and found it to be pretty confusing.

Would appreciate yall's opinion!

reddit.com
u/Franklin00798 — 4 days ago
▲ 19 r/learnrust+3 crossposts

Why adding Rust to my Python library made it 194x faster... and 5x slower.

I’ve been optimizing PythonSTL - a library that replicates C++ STL containers and algorithms in Python. To boost performance, I built a compiled Rust backend using PyO3 and Maturin.

After running benchmarks comparing Pure Python vs. Python + Rust vs. Pure C++ (O3), I encountered an amazing systems design paradox.

Here are the numbers and the engineering behind them:

The Wins (CPU-Bound Workloads):

• Bubble Sort (10k items): Pure Python took 5.4891s. Python + Rust took 0.0283s (a 194x speedup!).

• Binary Search (5k queries on 1M items): Python + Rust was 5.3x faster (0.0182s down to 0.0034s) by utilizing direct memory indexing without copying the list.

The Losses (FFI-Bound & Algorithmic Workloads):

• Stack (500k push/pop cycles): Python + Rust was only 1.47x faster (0.2324s vs 0.1581s). Why? Because calling push/pop from Python space crosses the Python-Rust FFI boundary 1 million times. The constant-factor cost of argument checking and GIL coordination dominates the runtime.

• Sorted Sets & Maps: Python + Rust was 5x slower! Why? Python’s native set/dict are highly optimized unordered O(1) hash tables. C++ STL compliance requires sorted keys, which we replicate using Rust’s B-Trees (running in O(log N) time) and calling back into the Python VM for comparisons.

The Core Takeaway:

Rust binary extensions are not a magic wand for performance. If your application does highly granular operations that frequently cross the FFI boundary, the boundary overhead will eat your performance gains.

But if you can bundle heavy calculations to run inside Rust with a single boundary crossing-it is an absolute game-changer.

Check out the project: https://github.com/AnshMNSoni/PythonSTL

I'd love to hear from other hybrid systems developers: how do you manage FFI overhead in your PyO3/Maturin libraries?

Thankyou.

u/AnshMNSoni — 5 days ago

Question about tests

Hi everyone, I’m now writing rust for about 1.5 years and I’m still wondering how you handle the visibility of the functions, structs or everything else for the tests.

Imagine I want to do a test for a specific function but not to export this one, how would you do it ? I know I could create a `mod test` in the actual file but I would like to get all the tests in one specific folder.

reddit.com
u/paquetalagadji — 4 days ago
▲ 2 r/learnrust+2 crossposts

How do you handle write-side reconciliation across multiple issue trackers in Rust? (idempotency + partial failure)

I want to read tasks from a bunch of trackers (Jira, Linear, GitHub Projects, Azure DevOps, Asana, Trello) into one canonical model, and the read side is mostly solved. The write side is where I keep getting bitten.

The problem: a single logical update on our end: say "move this task to In Progress and reassign", fans out into N tracker-specific mutations, each with different semantics. Jira wants a workflow transition (you can't just set status), Linear takes a typed state ID, Azure DevOps wants a work-item patch document, Asana has its own section move. Each can independently succeed or fail, and most have no transactional wrapper. So I'm left with the classic distributed-write mess: how do I make the fan-out idempotent, and what do I do when mutation 3 of 5 fails after 1 and 2 already committed?

What I've looked at:

  1. Outbox + per-tracker reconciler loop: Write intent to a local table, a worker drains it per tracker, retries on failure with backoff. This is the obvious answer and probably where I land, but it pushes the whole problem onto "is this mutation idempotent on retry?" and for some trackers I can't get a stable idempotency key, so a retry risks a duplicate transition or a double comment.

  2. Saga / compensating actions: Define a rollback for each forward mutation so a partial failure unwinds cleanly. Feels correct in theory, but writing a faithful inverse for "transitioned a Jira workflow" is genuinely hard, workflows aren't always reversible, and the compensation can itself fail. Starts to feel like more machinery than the problem deserves.

  3. Just make every write last-writer-wins and reconcile on next read: Simplest, and tempting for a local-first tool where the canonical state lives on-device anyway. But it papers over real divergence, if the remote write silently failed, the user thinks the board is updated when it isn't.

For the Rust folks who've built something like this: is the outbox-reconciler the consensus answer, and if so how are you getting idempotency for APIs that don't hand you a key? Or is there a pattern I'm missing that sidesteps the per-tracker inverse problem? I'd rather not reinvent a wheel if there's a crate or an established shape for this.

(Context for disclosure: I'm building Meridian, a local-first dev-worklog daemon, so this write path is something we ship, not a toy.)

reddit.com
u/Akarsh_Hegde — 6 days ago

Why does one work and the other doesn't?

fn main() {
    let mut s = String::from("hello world");

    let x = *get_unrelated_int(&s); // compiles
    let x = get_unrelated_int(&s);  // doesn't
    
    s.clear();

    println!("{x}");
}

fn get_unrelated_int(_s: &String) -> &i32 {
    &42
}
reddit.com
u/great_escape_fleur — 6 days ago
▲ 12 r/learnrust+1 crossposts

Built a multi-tenant real-time messaging server in Rust (Axum + Tokio + Redis + Kafka + Postgres) - would appreciate feedback

I am a final year ECE undergrad student, mostly self-taught on the systems side. Spent the last few months building Yappa-RT, a WebSocket messaging server meant to be droppable into a SaaS product that needs chat (DMs, group chats, broadcast channels) without one tenant ever being able to see another tenant's traffic. Sharing the architecture in case it's useful to someone else working on similar problems — and honestly because I'd rather have more experienced people poke holes in it now than find out the hard way later.

The core problem: stateless horizontal scaling for WebSockets is annoying because a connection lives on exactly one node, but messages need to reach users connected to any node.

How it's wired:

  • Every yappa-rt instance is identical and stateless. Connections are tracked locally in a DashMap-based registry (lock-free), but cross-node delivery happens through Redis Pub/Sub — each node subscribes to user:*:* and group:* patterns and only has to deliver to its own locally-connected sockets.
  • Durability is decoupled from delivery: every message also gets produced to Kafka, consumed in batches (500 msgs or 250ms, whichever first), and bulk-inserted into Postgres using UNNEST array expansion so one INSERT writes the whole batch instead of one round-trip per row.
  • There's a direct persistence mode that skips Kafka entirely and writes straight to Postgres — useful for demos/local dev where running a Kafka broker is overkill.
  • Backpressure: each connection gets a bounded mpsc channel (256 capacity). If a client can't keep up and the channel fills, it gets evicted instead of letting one slow consumer back up the whole fanout path.
  • Tenant isolation is enforced with a Redis Lua script for atomic per-tenant connection counting, using {tenant_id} hash tags so the whole check stays on one Redis Cluster slot.
  • DM conversation IDs are deterministic — sort both user IDs, concatenate, SHA-256, take the first 16 bytes as a UUID — so the same pair always lands in the same conversation regardless of who messages first, no separate lookup needed.

Stack: Axum (ws feature) for the HTTP/WS layer, Tokio for everything async, rdkafka for Kafka, redis-rs with the connection-manager feature for pooled pub/sub, sqlx for Postgres, jsonwebtoken for auth (HS256, pinned, with iss/aud/exp validation).

Auth is a separate Node service issuing short-lived (5 min) access tokens plus an HTTP-only refresh cookie — kept it out of the Rust binary so the messaging server doesn't own credential storage.

Happy to go deeper on any piece of this — the Redis Lua script for tenant limits, the Kafka consumer's manual-commit/flush-on-shutdown logic, or the connection registry's eviction behavior were the parts I iterated on the most. Also open to a code review if anyone wants to poke holes in it — this is still pre-1.0 and I'd rather find the sharp edges now.

Live instance: yappa.perceptionlabs.tech
Notion Docs: Notion

reddit.com
u/Western_Job9800 — 6 days ago
▲ 83 r/learnrust+1 crossposts

Conceptual Model for Ownership Types in Rust

Programmers learning Rust struggle to understand ownership types, Rust’s core mechanism for ensuring memory safety without garbage collection now you can see exactly what's permission is going on with the code
https://8gwifi.org/online-rust-compiler/

u/anish2good — 7 days ago
▲ 5 r/learnrust+2 crossposts

File archive tool

rust-file is a small Rust archive tool. Given a directory, it merges all files into one archive, compresses it, encrypts it, and can later restore the original files

github.com
u/Negative_Effort_2642 — 7 days ago

Rust habits you grew out of? Drop the beginner pattern and what you do now

Trying to start a thread on the little novice habits we all picked up early in Rust and what the cleaner version looks like once it clicks. Not talking about huge architecture stuff, just the small everyday patterns that quietly get better as you go.

I'll throw out a couple to get it going:

1. Cloning to dodge the borrow checker → just borrow

Reaching for .clone() the second the borrow checker complains:

fn process(data: Vec<u8>) -> usize {
    data.len()
}

let data = vec![1, 2, 3];
let len = process(data.clone()); // clone so we can still use data after
println!("still have {} bytes", data.len());

Take a slice instead and the clone disappears:

fn process(data: &[u8]) -> usize {
    data.len()
}

let data = vec![1, 2, 3];
let len = process(&data);
println!("still have {} bytes", data.len());

2. Rigid param types → flexible impl Into<String>

Taking String forces the caller to allocate up front, and taking &str just pushes the .to_string() inside so you allocate even when they already handed you an owned String:

struct User {
    name: String,
}

impl User {
    fn new(name: String) -> Self {
        User { name }
    }
}

User::new("scadoshi".to_string()); // caller has to build the String themselves

impl Into<String> lets them pass whichever they've got, and only allocates when it actually has to:

impl User {
    fn new(name: impl Into<String>) -> Self {
        User { name: name.into() }
    }
}

User::new("scadoshi");               // &str works
User::new(String::from("scadoshi")); // owned String moves straight in, no extra copy

What are yours?

reddit.com
u/scadoshi — 8 days ago
▲ 52 r/learnrust+1 crossposts

Why doesn't type inference help me here?

    let contents : Vec<char> = read_file!(file_name).chars().collect();

Why do I have to specify like the Vec<char> type annotation? I have seen this in the following case too:

let args : Vec&lt;String&gt; = std::env::args().collect();

Is this something related to .collect() method ?? I'm really confused here

reddit.com
u/capedbaldy475 — 9 days ago
▲ 19 r/learnrust+1 crossposts

Please help finding articles

Some time ago, like last year, I was reading an article about type level programming which mentioned a technique of using some main/head trait to coordinate compile time data across a crate. My admittedly hazy recollection is that this allowed compile time type information to be set in one part of the code and used in another part without the user needing to explicitly connect those parts.

Sorry this is a bit vague, Google is naturally no help at all and an extensive search of my browser history has been far from enlightening

reddit.com
u/aPieceOfYourBrain — 8 days ago