Skip Navigation
code_review

Code Review

  • [Rust] Implementation of an algorithm I invented - RANDEVU

    I came up with an algorithm and implemented it in Rust. I want to ensure the code is of sufficient quality before releasing it on Crates.io and GitHub. You can also find more info about the algorithm and its purpose there.

    I'm eager to hear your feedback and thoughts and am open to ANY suggestions that may help me improve the code further. The code should be performant, clean, easy to use, idiomatic, etc. I'm also looking for potentially better names for certain variables and stuff.

    Note that some things have changed a bit since the last release (for example - the hash calculation has been changed from blake3(blake3(OBJECT) || blake3(DATE)) to blake3::keyed_hash(DATE, OBJECT) to improve performance by eliminating 2 out of 3 hash calculations), but the README is still valid (and hopefully at least somewhat decent source of info about the algorithm - I did my best trying to explain stuff, but I'm still looking to improve it further in the future).

    The functions can panic if they are given a date where the year is outside of the 0000 to 9999 range. I'm not sure if I should make the function return the result/option instead of panicking since I'd like to avoid having to unwrap() the output and would prefer if the function returned just a simple u32/chrono::NaiveTime (but I'm open to changing my mind on this one).

    I'm also curious if there is a cleaner way to create a key from a date. Previously, I've been using format("%Y-%m-%d") to convert it into a string slice and copy it into the key array, but I've found that approach to be very slow (over 50% of the CPU time was being spent just for that alone), so I opted out for an approach you can see below.

    The newest function rdvt() is not yet documented anywhere, but I'll do my best to explain it here:   In addition to an object and a date (same as rdv()), it also takes a rank (which is a positive integer - u32). The function calculates the keyed blake3 hash of an object, using the date and a rank as key, and uses the resulting (pseudorandom) bits to generate and return a random uniform time (chrono::NaiveTime) between 0h and 24h (down to nanosecond precision). Time is calculated by taking the first bit of the hash and in case it's a binary one - 12h is added to the time, then we add 6h if the 2nd bit of the hash is a one, 3h for the 3rd bit, 1.5h for 4th and so on until the increment reaches the small enough value where it doesn't contribute anything to the time (when it becomes less than 1ns, essentially).   This means if all of the bits in the hash were zeros - time would be zero, and if they were all ones - time would be 23:59:59:999:999:999h (the very last and highest possible value). The code short-circuits and stops earlier than going through all 256 bits since we usually only need around 46 bits before the increment becomes smaller than 1ns (the code stops only in case the sum of tiny sub 1ns increments can't contribute enough to change the last digit in the total time (even if all of the rest of the bits in the hash were to be ones))):

    Feel free to ask ANY questions regarding the code, the algorithm, its function, use cases, or anything else you'd like explained or clarified.

    Here's the code (I haven't written any tests yet, so they are not included for review):

    rust //! The official Rust implementation of the [RANDEVU](https://github.com/TypicalHog/randevu) algorithm //! //! # Example //! rust //! use chrono::Utc; //! use randevu::{rdv, rdvt}; //! //! fn main() { //! let object = "THE_SIMPSONS"; //! let date = Utc::now(); //! let rdv = rdv(object, &date); //! let rdvt = rdvt(0, object, &date); //! //! println!("Object {} has RDV{} today with RDVT0 at {:?}", object, rdv, rdvt); //! } //! ```

    use blake3; use chrono::{DateTime, Datelike, NaiveTime, TimeDelta, Utc}; use itoa;

    /// Returns the 32-byte KEY [u8; 32] created from a given DATE &DateTime<Utc> and an optional RANK Option<u32> fn create_key(date: &DateTime<Utc>, rank: Option<u32>) -> [u8; 32] { let mut key = [0u8; 32];

    let mut year = Datelike::year(date); let mut month = Datelike::month(date); let mut day = Datelike::day(date);

    let mut year_len = 4; let mut prefix_len = 0;

    // Add a prefix (-/+) if the year is not between 0 and 9999 (-YYYY-MM-DD / +YYYY-MM-DD) if year < 0 { key[0] = b'-'; prefix_len = 1;

    year = year.abs(); // Make year positive } else if year > 9999 { key[0] = b'+'; prefix_len = 1; }

    // Adjust year_len for very large years (both positive and negative) if year > 9999 { year_len += 1; if year > 99999 { year_len += 1; } }

    let full_year_len = prefix_len + year_len;

    // If a rank is provided, write it into the key after the date, separated by an '_' if rank != None { let mut buffer = itoa::Buffer::new(); let rank_str = buffer.format(rank.unwrap()); key[7 + full_year_len..7 + full_year_len + rank_str.len()] .copy_from_slice(&rank_str.as_bytes()[..rank_str.len()]);

    key[6 + full_year_len] = b'_'; }

    // Write the day into the key key[5 + full_year_len] = b'0' + (day % 10) as u8; day /= 10; key[4 + full_year_len] = b'0' + day as u8;

    key[3 + full_year_len] = b'-';

    // Write the month into the key key[2 + full_year_len] = b'0' + (month % 10) as u8; month /= 10; key[1 + full_year_len] = b'0' + month as u8;

    key[full_year_len] = b'-';

    // Write the year into the key for i in (prefix_len..full_year_len).rev() { key[i] = b'0' + (year % 10) as u8; year /= 10; }

    key }

    /// Returns the RDV value u32 for an OBJECT &str on a specific DATE &DateTime<Utc> /// /// RDV = number of leading zero bits in blake3::keyed_hash(key: DATE, data: OBJECT) pub fn rdv(object: &str, date: &DateTime<Utc>) -> u32 { let hash = blake3::keyed_hash(&create_key(date, None), object.as_bytes());

    // Count the number of leading zero bits in the hash let mut rdv = 0; for &byte in hash.as_bytes() { rdv += byte.leading_zeros();

    if byte != 0 { break; } }

    rdv }

    /// Returns the RDVT time DateTime<Utc> of a given RANK u32 for an OBJECT &str on a specific DATE &DateTime<Utc> pub fn rdvt(rank: u32, object: &str, date: &DateTime<Utc>) -> DateTime<Utc> { let hash = blake3::keyed_hash(&create_key(date, Some(rank)), object.as_bytes());

    // Calculate the time using bits from the hash let mut total: f64 = 0.0; let mut increment = 12.0 * 60.0 * 60.0 * 1_000_000_000.0; // 12h in nanoseconds for (i, byte) in hash.as_bytes().iter().enumerate() { for j in (0..8).rev() { let bit = (byte >> j) & 1; if bit == 1 { total += increment; } increment /= 2.0; } // Stop once increments become too small to affect the total if i > 4 && (2.0 * increment) < (1.0 - total.fract()) { break; } }

    // Construct the RDVT time from total let rdvt = date.with_time(NaiveTime::MIN).unwrap() + TimeDelta::nanoseconds(total as i64);

    rdvt }

    ```

    10
  • [C] Having a runtime error with a simple function

    Hello, I am new to this community, as well as to coding in general. I am having fun learning C, and I've generally been able to work through/slam my head into problems until they make sense, but I am confounded by this discrepancy, and I am hoping to have some help with it:

    printf("%%c);

    Output: %c

    ----------------------

    ``` #include

    void textGreen(const char* text) { printf("\033[32m%s\033[0m", text); }

    int main() { textGreen("%%c\n"); return 0; } ``` Output: %%c.

    Since printf is wrapped into the function, should the text not be outputting with the same behavior? Why is my terminal printing this code without escaping the percent sign? FWIW, the text is green, at the very least.

    I am using Ubuntu 23.10, the code was written in KATE, it was compiled in GCC, and it was run on the basic GNOME terminal.

    5
  • [Rust] Simple predictive text review

    I wrote a simple algorithm for predictive text that uses preceding words as context. Without looking at prior, it was an attempt as seeing what I could come up with.

    The goal is for it to be incorporated in chorded input and pick the best candidate for the entered chord with the given context. Chorded input is the method of hitting all keys for a word simultaneously instead of hitting each key individually in expected order.

    E.g you've typed "this is the worst" and hit the chord "aet", which word should be chosen? ate? tea? eta? This algorithm is there to answer that.

    What I'm looking for in the code review in order of importance:

    • documentation (is it understandable? are there things missing? ...)
    • code architecture, code structure (function should be a member? composition could be changed? clarity, ...)
    • algorithm review (optimisations, improvements)
    • variable and class names (naming things is hard)
    • rust specific stuff (f64 instead of u32 maybe? dyn vs impl? ...)

    The code is linted and automatically formatted.

    2
  • [Rust + Tauri + React] Cryptography Usage Review
    gitlab.com src-tauri/src/app/crypto.rs · master · treedome / treedome · GitLab

    A local-first, encrypted, note taking application with tree-like structures, all written and saved in your computer.

    src-tauri/src/app/crypto.rs · master · treedome / treedome · GitLab

    I'm making an offline first, note taking application made with rust+tauri. I've reviewed this before with one of my friend and he checks everything from the way I use the library, how I uses my nonces, salt, and the like. But It's never a bad thing to ask you guys for some thought, if any.

    Please take it slow, assume the best, and be gentle with me.

    3
  • Tips on making code reviewable on source forges

    Source forges like Gitlab, Gitea, Forgjo, Github, and others do not allow directly leaving comments on code. However, they all do allow leaving comments on pull/merge requests and individual commits. This unfortunately doesn't work for snippets like Gitlab Snippets, Github Gists, etc. .

    We can however use these to our advantage and use workarounds in order to make certain parts of our code reviewable:

    Snippets

    Create a repository to host your snippets (if you don't have one already), add your snippet of code as one commit to the repository (can be in a throwaway branch, the master branch, whatever). Share that commit link!

    Larger changes

    If you have code that belongs together, it is already in your repository, and is spread out over multiple commits, fear not! Once again, you can use the power of temporary branches. With these methods you can even have your entire repo reviewed.

    A commit to review

    Create a new branch, delete the parts of the code you want reviewed, create a revert commit, and share that link!

    A PR to review

    This requires 2 branches. If you've read the steps above, you already know where this is going.

    Create a branch (deleted), delete the code and commit it. Create a new branch (revert) from this point and revert the previous commit. Now you can push both branches to your source forge and create a new merge request to merge revert into deleted.

    -----------

    If you have other tips, share them!

    3
1 Active user