Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use bit structs in a read-only context. #17

Open
Borketh opened this issue Apr 8, 2023 · 4 comments
Open

Unable to use bit structs in a read-only context. #17

Borketh opened this issue Apr 8, 2023 · 4 comments

Comments

@Borketh
Copy link

Borketh commented Apr 8, 2023

Good afternoon! I've been writing something heavily using this library but I came across a roadblock.

Problem

The way GetSet are created means that I need mutability of a bit struct to be able to read from it, which is not necessary nor possible in some cases.

Example

use bit_struct::*;

bit_struct! {
	// Useless struct for demonstration purposes
	pub struct Halfling(u8) {
		first_half: u4,
		second_half: u4
	}
}

impl Display for Halfling {
	// note immutability of self
	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
		writeln!(f, "The halves together make {}", self.first_half.get().value() + self.second_half.get().value())
	}
}

This will not compile because .first_half() and .second_half() take &mut self to make their GetSets, which the signature of Display::fmt doesn't permit. In this use case I don't need to modify the Halfling at all and can't, but it insists it must be mutable.

Solution?

I understand why GetSet needs to be constructed with a mutable reference, so I propose a Get or similarly named struct with read-only privileges that will work in this context. How that would work, I'm not sure.

By convention it would make sense to change all generated field GetSet functions to mut_[field name] and make the existing ones return Get structs instead, but this would break everything wholesale. How would you prefer to implement this? I would be willing to do the legwork in a PR.

@andrewgazelka
Copy link
Contributor

andrewgazelka commented Apr 8, 2023

When I started making bit-struct, I tried to make everything be in the form self.get().first_half() and self.set().first_half(set_value) to avoid this problem, but I ran into issues (I forgot what).

You can always copy Halfling and do GetSet on it, although is it not ideal.

honestly, I'd argue that since proc macros are much better supported in IDEs we could use proc macros for a lot of this and release a major breaking change where we rework everything. What are your thoughts regarding this?

@Borketh
Copy link
Author

Borketh commented Apr 8, 2023

So you mean like this?

use bit_struct::*;

impl Display for Halfling {

	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
		let temp = &mut self.clone();
		writeln!(f, "The halves together make {}", temp.first_half.get().value() + temp.second_half.get().value())
	}
}

I mean it does work but it does look a little funky.

I don't see how proc macros could help here, but then again I'm not experienced in writing them at all, so if you have an idea go for it! I can't think of a reasonable syntax for separating get and set just yet but I think I'll sleep on it :)

@andrewgazelka
Copy link
Contributor

andrewgazelka commented Apr 8, 2023

So you mean like this?

use bit_struct::*;

impl Display for Halfling {

	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
		let temp = &mut self.clone();
		writeln!(f, "The halves together make {}", temp.first_half.get().value() + temp.second_half.get().value())
	}
}

I mean it does work but it does look a little funky.

I don't see how proc macros could help here, but then again I'm not experienced in writing them at all, so if you have an idea go for it! I can't think of a reasonable syntax for separating get and set just yet but I think I'll sleep on it :)

I think the issue with not being able to have a Get and a Set half was something related to it being really hard/anoying to do without proc macros, but again... it's been a long time since I made this

Also I think you can do

fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
		let temp = *self;
		writeln!(f, "The halves together make {}", temp.first_half.get().value() + temp.second_half.get().value())

which is slightly cleaner

@Borketh
Copy link
Author

Borketh commented Apr 8, 2023

That does work for the time being.
I'll let you know if I have any other ideas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants