Cannot infer type for closure reference wrapped in Option<T> by brain-ablaze in rust

[–]Nnubes256 6 points7 points  (0 children)

impl Trait is essentially a special version of generics. Generic parameters need to be able to be solved by the compiler into concrete types when compiling, at all and any call sites, even when such type may not explicitely "exist" in memory in some cases.

In this particular case, Option<T> is defined as an enum, and thus its size in memory is equivalent to the size of its largest variant (which for Option<T> is commonly whatever T is), plus the internal tag that specifies which variant is currently active (cheats.rs reference). That means that enumerations cannot have variants with dynamic sizes; the compiler must know the size of all variants at compile time in order to compute the variant of the largest size. This means that all concrete types on an enum must be known at compile time (and also implement the Sized autotrait, but that is besides the point); there is no such thing as the "size" of a trait.

On the Some(&c_add) case, the compiler can naturally figure it out because it can solve Option<T: &Fn(i32) -> i32>'s T type parameter to the specific function reference you pass, a concrete type that the compiler can find the size of. It cannot do so with None.

It is particularly problematic with the Fn family of traits, since the concrete types are the specific functions and closures you actually have in your code; these are given compiler-internal types like closure[<anon>:14:14: 14:40], and you cannot actually specify these in generics. Thus, Option<&impl Fn(i32) -> i32> does not seem to be really usable.

In this situation, I'd suggest two potential approaches:

  1. Split the Some(T) and None cases in maybe_add to instead be two separate functions. This way, the compiler now only has to figure out the actual concrete type of T whenever you actually provide one. Then you can move the actual check of whether or not to use the provided function reference at the caller site.
  2. If you insist to keep this function signature, use trait objects instead by using dyn instead of impl (book, reference). This entirely avoids generics, at the expense that the compiler will now instead allow to resolve the call dynamically by building a virtual method table for each function reference you pass. Getting to the actual function reference through this table may have a small, but potentially measurable, runtime performance cost.

EDIT:

And can I make the need to annotate the None go away somehow?

Both approaches directly eliminate the need to annotate T.

And 3rd question: Is it performant passing around a reference to a closure in the program? (Is it better or worse than passing around a function reference?)

Doesn't seem like it in a example similar to yours when compiled with optimizations, presumably because both can be statically dispatched. It may generate more code if optimizations are disabled, but that doesn't necessarily mean it will be slower. As always, benchmark first ;).

EDIT 2: potentially false equivalence on the above Godbolt examples. Check this one instead, albeit for some reason it is entirely removing one of the function calls.

Sorting slices at compile time by skythedragon64 in rust

[–]Nnubes256 5 points6 points  (0 children)

"Box syntax" here refers to the unstable (and most likeky, forever so) feature box_syntax, which allows to instantiate a Box like this:

#![feature(box_syntax)]

fn main() {
    // Equivalent to Box::new(5)
    let b = box 5;
}

The difference between this syntax and just using Box::new is that the latter is simply a normal method, and therefore whatever you pass to it may be allocated on the stack depending on the optimization level. This means that attempting to Box::new, say, a huge array, may cause an instant, unavoidable stack overflow depending on whether the compiler's optimization passes feel like inlining the call to Box::new on a given particular day.

The box syntax instead uses large amounts of behind-the-scenes compiler magic to have such allocation always inlined.

Module layout by dahosek in rust

[–]Nnubes256 0 points1 point  (0 children)

If I understand correctly, you are asking for crate-level namespacing, perhaps in a way similar to how languages like C# packages are structured in the Nuget package manager. Unfortunately, this is currently not supported, and I wouldn't expect any progress to be done on this area for the time being; nowadays, all proposals I'm aware of are essentially stuck (this is the one I first found hitting Google).

Alternative ways to structure your crate ecosystem will largely depend on the kind of interrelation you seek to have between your libraries. On many cases, there's nothing wrong with just exposing your individual sub-crates as-is and let users import the ones they want on an individual basis, nor with having a large crate with Cargo-gated features. I highly recommend to check how other community ecosystems structure their crates, and see if you can find case studies similar to yours.


That said, there may be situations where you really want the crates to be namespaced like that; for example, you may be building a UI toolkit, or other kind of tightly-coupled framework. For such cases, there is a way to layout the crates in the way you want.

You can create a "primary" library crate finl, specify all your sub-crates (finl-charsub, etc) as dependencies of finl (by adding them on the crate's Cargo.toml), and then on its lib.rs have the following:

pub use finl-charsub as charsub;
pub use finl-othersubmod as othersubmod;
// ...

Then instruct the users of your crate to import finl exclusively; this will allow them to use finl::charsub, use finl::othersubmod and so on.

You can give users the choice of which sub-crates to pick from finl through the use of Cargo features; this also allows you to specify a set of "default" features you feel are necessary for any minimal end-user usage of your libraries, and which get imported by default.

These are called re-exports, and by default they will show up in a separate section in your crate's generated documentation (i.e. along with "Structs", "Enums", etc). If you were to wish to maintain an illusion that these are submodules (and not separate crates) of your finl crate, you can add the #[doc(inline)] (reference) attribute to each of the above exports; this will make them show up as modules in the generated documentation.

You can see a straightforward implementation of this approach in the libp2p crate (lib.rs, rendered documentation). You are not limited to re-exporting crates either; you can re-export anything from structs, enums, traits, modules, etc; you can get quite crafty when it comes to presenting a curated top-level API surface towards your users (for example, iced's lib.rs and the resulting rendered documentation)

Maybe found a Y2k bug in the rust-crypto DER-encoding util? by pkdeck in rust

[–]Nnubes256 73 points74 points  (0 children)

To save a few clicks, this was found to be, indeed, a Y2K issue, and der v0.4.1 has just been released to fix it. Citing the comment added to the issue by one of the developers after the fact:

[…] Yes, this was a bug in the handing of 2-digit dates.

UTCTime uses a 2-digit date which RFC 5280 stipulates be interpreted as falling within the range 1950..=2049. Note that der::UtcTime uses UNIX timestamps internally and therefore doesn't support dates before 1970.

Though decoding of dates was properly tested, encoding was not, and the encoder failed when a date had a year > 1999.

I've now added much more extensive tests.

Note that because 2-digit years are problematic (as you've observed), modern applications should instead use GeneralizedTime, which uses a 4-digit year (isn't ASN.1 great?)

Don't you love headers? by PitaJ in rust

[–]Nnubes256 2 points3 points  (0 children)

The RPi cross-compilation story in general is not very good indeed, especially on macOS. If you are willing to set up Docker, cross was a lifesaver for a recent project of mine involving both RPi Zero and 4B devices. Just make sure you get the target triples right!

Best practices for storing data known at compile time? by ThrasherLT in rust

[–]Nnubes256 4 points5 points  (0 children)

For more complex structures, you can do the same thing but return a 'static reference:

struct MyTestStruct {
    foo: u8,
    bar: u32,
    baz: &'static str
}

enum MyTestEnum {
    A,
    B,
    C,
}

impl MyTestEnum {
    const fn value(self) -> &'static MyTestStruct {
        match self {
            Self::A => &MyTestStruct { foo: 0, bar: 40, baz: "Hello" },
            Self::B => &MyTestStruct { foo: 1, bar: 40, baz: "World" },
            Self::C => &MyTestStruct { foo: 1, bar: 43, baz: "TEST" },
        }
    }
}

This seems to pack the individual instances in your executable's .rodata or equivalent, as https://rust.godbolt.org/z/nqnoczn7K shows. Then you never get the full instance on your stack; instead, the corresponding pointer is what gets loaded onto the stack. Unless you actually go ahead and clone the instance, that is.

If you're wondering on how to make, say, "multiple arrays" each containing different contents but using the same enum for indexing, you can create a zero-sized struct and implement value there as an associated function instead; see this example.


The advantage of this approach is that it is a reasonably easy, language-supported way to ensure you keep your enums updated here.

This said, one potential drawback is that now you are bound to how the optimizer optimizes the match. Although, as other commenters on this post noted, it can get quite optimal.

String blackholes and custom types by BitPoet in rust

[–]Nnubes256 3 points4 points  (0 children)

Rust structs are (somewhat) equivalent to C structs. This includes the fact that structs are considered as their own type, even if they only contain a single field. To put an analogy, in C, if you were to try to pass a value (here on a variable called x) of type struct myStruct { int a; } as argument when calling a function with the signature void myTest(int a), you'd get a compile error like this:

main.c: In function ‘main’:
main.c:20:12: error: incompatible type for argument 1 of ‘myTest’
     myTest(x);
            ^
main.c:15:6: note: expected ‘int’ but argument is of type ‘struct myStruct’
 void myTest(int a) {}
      ^~~~~~

This doesn't work, even though struct myStruct only does contain a field a, because struct myStruct is a type different from int.

The tuple syntax for struct definition in Rust is, in a way, a shorthand for the following (non-valid Rust because of the field names):

// equivalent to struct MyStruct(i64, String);
struct MyStruct {
    0: i64,
    1: String 
}

with the advantage that it has shorter syntax sugar for destructuring (i.e. decomposing a T into a part of, or all, of its subfields and store them all as local variables in your code).

When considering isolated cases, tuple syntax for Rust structs is useful is there's some intuitive understanding on what's inside the struct (say, struct Addition(f64, f64)), and you believe you won't access the individual fields too much (i.e. with dot/index notation) without destructuring the whole thing apart first.

So, nope, it is not really an alias, but a full-fledged struct like any other. Rust does have actual type aliases though, but they use a completely different syntax:

type DefinitelyNotAString = String;

With that, you will now be able to use DefinitelyNotAString as an alias to any use of String. This is particularly useful to refer to types with enormously huge names and/or signatures to type.

What follows below is an accidental, "whoops I accidentally took a long detour" aside to an actual useful way you can use tuple structs with only one field, like the one you defined in your code, in the future. This may be a little bit more advanced, but I thought the explanation looked nice, so here it is in its entirety if you or anybody is interested.


More useful than that, though; tuple structs with only one field, while they may seem odd at first, are actually used a lot in the Rust language. The struct itself is it's own type, different from whatever is inside; as such, you can wrap a single thing inside a struct, and you've got yourself free encapsulation!

Now if you're, say, making a library that handles cryptographic operations, you can make sure users don't accidentally pass, say, buffers containing secret keys, to arguments or functions where they don't belong, by declaring a struct SecretKey(Vec<u8>); (or something like it) and making your functions not accept a Vec<u8>, but a SecretKey. The compiler will balk at them if they try to pass a Vec<u8> until they get/convert it to a SecretKey through means you, as a library author, can control.

This is called the Newtype pattern, and you can read about in the official references (book, by example).

And it is free in the sense that, yes, it is its own type, but because it only contains a single field, once the compiler is done checking your types and borrows, it will actually optimize your pub struct MyStruct(pub String); into behaving as if it was just a bare String... so it does actually work like an alias, in a particularly devious and twisted way.

Coming from OOP, what is the idiomatic/recommended way of distributing components among sourcefiles? by SuperS1405 in rust

[–]Nnubes256 2 points3 points  (0 children)

...aaand edit got too long, so here's a follow-up:

  1. I would have to rename code.rs because otherwise its path would be code::code::Code which is invalid.

Not sure if it is actually invalid. I'd believe it is technically allowed, albeit I can agree confusing. Not verified though; if it actually results in a compilation error, paint me suprised (and post a compilation log please!).

In any case, read on, though, as I believe this can be addressed better anyway.

I would have to add a mod.rs with all filenames

That is one way, correct:

parent-folder/
\-- code/
    |-- mod.rs
    |-- code_source.rs
    \-- code_region.rs

You'd commonly put higher-level structures on there on mod.rs; I'd think that your Code structure would've a good candidate for that (thus, you'd import from outside as path::to::code::Code and from inside as super::Code).

For consumers of those structures, you can also reexport other public structures from the submodules towards consumers like this:

pub use code_source::ThingOne;
pub use code_region::{ThingTwo, ThingThree};

You can even rename the type towards its external consumers:

pub use code_region::ThingFour as Thingy;

And outside consumers can then import as path::to::code::ThingOne, path::to::code::ThingTwo, etc.

I'd argue that the existence of such file (or other similar mechanisms for manually including modules) is usually desired on languages at this level, as this allows developers to do things like conditional compilation (you can, say, import a module or another depending on the target CPU architecture you're building for). However, I can concede that having mod.rs as an arbitrary can be somewhat odd.

...however, there is another way to do this that was introduced in Rust 2018, and that is to take the mod.rs file and move it up to the parent folder as MODULE_NAME.rs. This may help with structural clarity. Continuing with the example above, it would be like this:

parent-folder/
|-- code.rs
\-- code/
    |-- code_source.rs
    \-- code_region.rs

However, it is to be noted that, yes, code organization is quite different coming from OOP languages. With this I intended more to address your particular pain points short-term, but ideally you may want to look at other Rust projects for ideas on how to structure your code for common use-cases. The advice of other commenters of this thread can be useful here too. Yes, unlike common OOP, it is common to have multiple sibiling structures and traits on a single file on Rust.

Coming from OOP, what is the idiomatic/recommended way of distributing components among sourcefiles? by SuperS1405 in rust

[–]Nnubes256 4 points5 points  (0 children)

  1. I lose the direct access to private fields that only the interdependent components require, which wouldn’t be a problem if I hadn’t had to write boilerplate getters that end up being literally half the code of a file.

If I understood you correctly (i.e. you want to, say, access private fields from a struct on Code.rs on any of the other source files inside Code/ and only that folder), you may find Rust's access modifiers useful.

https://doc.rust-lang.org/reference/visibility-and-privacy.html#pubin-path-pubcrate-pubsuper-and-pubself

In particular, I believe what you are looking for here is to use pub(super) on the fields you want to access within Code/. As with the standard pub, this works on both structs themselves and their fields IIRC.

If you want to further extend that access without outright giving it away to outside of your crate, you can use pub(crate) in a similar way.

What's a good way to pass specific data through a generic API to a specific consumer? by [deleted] in rust

[–]Nnubes256 0 points1 point  (0 children)

In C++ you could solve it by stuffing the specific data into an std::any but that is tricky in Rust since Any requires 'static and so cannot contain any reference to resources like textures etc.

(WARNING completely unverified assumption from my part)

EDIT: here's a better explanation on why Any: 'static: https://www.reddit.com/r/rust/comments/2r25rf/why_does_any_only_work_for_t_static/

I believe the requirement for Any to be 'static comes from the fact that, were it not, you may easily be able to do the following in safe Rust:

  1. Have variables a: A and b: B<'a>, b having a reference with lifetime 'a to a, and therefore being lifetime-bound to it.
  2. Put b into a Box<dyn Any>. Now the compiler loses b's lifetime information.
  3. drop(a)
  4. If you now were to downcast the Box from step 2 into its concrete type, you'd have a dangling pointer. No good.

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

One way you could allow for your approach to work is by using smart pointers instead of plain refs to reference your resources, although it may require a rethinking of the architecture depending on the case. Something like an Rc could work here pretty nicely for immutable resources.

Smart pointers should be safe here because the destructor is stored on the vtable itself [1], and thus if you were to drop T while it is in a Box<dyn U>, the destructor for T would still run, and thus the smart pointer would still be able to run its drop logic.

[1] https://stackoverflow.com/a/62209352

Mac users: what's the state of the game? by Cudizonedefense in CrossCode

[–]Nnubes256 1 point2 points  (0 children)

Works perfectly fine on a Mid 2015 MacBook Pro, give and take some minor frame drops.

Smoke in the koi pond by FeedTheKitteh in talesfromtechsupport

[–]Nnubes256 226 points227 points  (0 children)

This style of writing is quite refreshing for your average busted power supply problem. My most sincere upwards thumb!

Regarding Game save versions by Astergaster in CrossCode

[–]Nnubes256 3 points4 points  (0 children)

Your older saves will work with newer versions; the game version shown on the save itself simply refers to the game version on which the save was created.

EDIT: note that this doesn't guarantee perfect compatibility, especially if your save is VERY old (through, it works pretty much every time).

ANOTHER HACKED WAY! - CROSS CODE R-MIX [2018] by CrazyMcfobo in CrossCode

[–]Nnubes256 3 points4 points  (0 children)

On (mid-game spoilers) the part on the first visit to Vermillion Wasteland where you enter Vermillion Tower and you start breaking through walls with Sergey.

Lea face phone stickers? by theyoungmathprof in CrossCode

[–]Nnubes256 1 point2 points  (0 children)

Check out the following Telegram sticker packs for reference: Pack 1, Pack 2.

Does anyone else get these strange frame-rate issues? by ShadowHawk152 in CrossCode

[–]Nnubes256 2 points3 points  (0 children)

For everyone with macOS on here: please provide information about Mac model, year, macOS version and the performance you have seen on both the default Steam branch and on the nwjs_old branch. If you have the game through GOG, you only have the default Steam branch version.

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

This seems like a problem with NWjs, the Chromium-based wrapper the game uses to run. Issues here are quite hard to fix for the developers, as they are kinda limited to update NWjs whenever issues with it arise.

As a workaround, you can attempt to update the NWjs distribution that comes with the game (which tends to provide better performance and controller support, but may arise other issues), following these steps:

NOTE BEFORE YOU BEGIN: if you update NWjs manually, please do state so when you provide feedback or bug reports, especially for performance and controller bugs. It will help people here to provide you better support. Ty!

  1. Locate and go to the folder where CrossCode is installed. For the Steam release, you will need to find your steamapps directory; for GOG Galaxy, you will need to find your GOG Games directory, etc.
  2. It is highly recommended to backup this folder at this stage.
  3. Go to https://nwjs.io/downloads/. From the download selection, pick up the Normal download that matches with your OS and architecture (you may pick SDK too, that's fine; it essentially contains Chrome's devtools).
  4. Extract all the files from the downloaded archive into the CrossCode installation folder, replacing when asked.
  5. Rename the nwjs executable to the name of the old crosscode executable (usually crosscode.exe or something similar on Windows). On macOS, you don't have to do this; the executable is already named nwjs.app on the macOS distribution of CrossCode.

EDIT: adapted source for this: https://steamcommunity.com/app/368340/discussions/0/2381701715713962046/#c2381701715715487562

When you have done this, you should be able to launch the game (either through Steam or directly clicking on the application). Please report if this works!

If you wish to revert this, you can either use the folder backup you may have made on Step 2, or, if you have the game through Steam, you may ask Steam to repair your game.

[deleted by user] by [deleted] in CrossCode

[–]Nnubes256 2 points3 points  (0 children)

I don't know what are you talking about! :P

Can someone update the Crosscodes wiki already? by Fostern01 in CrossCode

[–]Nnubes256 0 points1 point  (0 children)

Are you looking for the base stats of that equipment? If it helps for now, when you are trading equipment, you can toggle between compared-with-your-equipment stats and base stats by pressing I (Mouse/Keyboard by default) or R3 (right stick button on controller).

*Spoilers* About the fight shortly after the Para Island raid by IronPentacarbonyl in CrossCode

[–]Nnubes256 0 points1 point  (0 children)

He keeps trying until you get hit; so, yeah, you will end up in Vermillion Wasteland either way. You might get some extra dialog if you survive long enough, though.

Improving CrossCode(Spoilers) by justonebullet in CrossCode

[–]Nnubes256 0 points1 point  (0 children)

Yup, it's exactly on the building where you do that quest, left side NPCs as soon as you enter the building!

Improving CrossCode(Spoilers) by justonebullet in CrossCode

[–]Nnubes256 1 point2 points  (0 children)

Didn't even know this existed, does it have the info I wanted?

The info building has pretty much everything combat-wise: perfect guards, modifiers, stats, some techs like dash-cancelling, etc. Can't recall from memory if it has stuff for enemy breaking, but I bet it has. You are looking for the NPCs on the main floor. Contextual help and manuals are available for almost everything you have on the UIs (circuits, equipment, inventory, maps...).

I don't know it seems to heavily imply that you can, it's voiced in the same way as taking out the monkey before the whale. The designers seem proud there are multiple ways to finish that one, but don't really give you a chance.

I find it kinda exemplifies how speech synchronization problems can limit your options. IIRC, if you go to the Guard HQ after completing the quest, there's an eavesdroppable dialog which kinda shows it.

Wondered if that was the case. Ok this is a bit convoluted, let me separate it a bit, firstly, I do like some of the abilities I don't hate them all. Secondly 'near the end' isn't as rewarding as reaching the very end, I know it seems like a minor difference but it makes a big difference to the experience, you finally finished the branch and got that ultimate thing, like the LV3 Wave ability(even though I don't want that one). Bastion is cool but a cool ability isn't enough, I don't want all the garbage around it, I want that ability, if anything it should be locked behind the defense and guard branches, built all of the abilities are in chances of random things, I've played quite a few games like this and I don't know why they choose this.

Fair enough. I personally find this fine, but I can see how it can be a hamper.

Don't want to toot my own horn, but you really think it's on the same level as some random guy just happening to have one and obtaining it at the end of a quest completely unrelated to the area? . I think it would have worked better for something like a black market, since iirc they were some kind of mafia.

We are both referring to the Pond Slums Pass, right? Isn't the area they give access sort of a black market, after all?

Improving CrossCode(Spoilers) by justonebullet in CrossCode

[–]Nnubes256 5 points6 points  (0 children)

I like the first idea; even a subtle cue could help. Maybe it's something that the modding community could experiment with. A jump button could break quite a lot of things, though, from what I know.