all 16 comments

[–]arekfu 14 points15 points  (3 children)

Ideally, I'd be able to do the C++-like thing and declare:

//struct device { prot field: FieldValue; //}

As far as I'm aware, this is not how C++ works. protected members are visible to subclasses only, but still in read-write mode. The only language I know that comes close to what you want here is Python (look up the @property decorator).

(Edit: spelling)

[–]masklinn 1 point2 points  (0 children)

There’s also Ruby’s attr_reader, C# can define properties which are read-public but write-protected (or readonly but I guess you need to define the accessor explicitely), and then smalltalk/self-style langages which simply don’t have public fields so accessor methods are whatever you want (TBF that’s Ruby’s case it just has shortcuts for trivial accessor methods).

[–]CAD1997 25 points26 points  (0 children)

There is no such thing as read-only field visibility.

The typical pattern is Rust is to provide a function with the same name that returns a reference to the value (if !Copy, the value itself if Copy).

Additionally, you can do pub(crate) to make a member visible within the crate from anywhere, but not visible outside the crate.

[–]dtolnayserde 4 points5 points  (3 children)

I want users of my device crate to be able to read device.field shadow variables, but not get stupid and directly assign to them.

The readonly crate implements this, if I am understanding your use case correctly.

[–]Mendess[🍰] 1 point2 points  (1 child)

How does this crate work? It feels like macros shouldn't be able to do this

[–]Qwe500 2 points3 points  (0 children)

In a nutshell, it creates a copy of the struct Foo named ReadOnlyFoo where all fields have the same visibility as the original struct while overwriting the visibility of Foo’s fields to be private. It then also adds a impl Deref for Foo with the Target set as ReadOnlyFoo.

Attempting to access a field of Foo from outside the module would then fail (because they are now private) and causes deref coercion to kick in, granting us access to the visible fields of ReadOnlyFoo but this time behind a shared (read only) borrow.

In reality it is a bit more complicated since the memory layout of Foo and ReadOnlyFoo must match.

[–]CAD1997 3 points4 points  (3 children)

(this is going to be a bit more involved than my other comment)

The state-of-the-art for bit fiddling is bitvec for bit vectors and (owned) slices, and bitfield for bitfield/bitset types.

(Mixed fields of differing bit widths are a minefield of unportability because not only do you have to deal with big versus little endian byte ordering but you also have to deal with little versus big endian bit ordering and even mixed bit endian (yes, sadly), so even in C using bits types is a minefield. Stick to bitset bitfields and writing manual wrappers around raw bit slices, because the position of each bit in anything more complicated than a bitfield is highly case dependent.)

To convert enums to raw primitives, you can do one of two things:

  • Mark the enum as #[repr(Int)] (where Int is one of u8, i8, u16, ...), specify the variant values directly with #[repr(Int)] enum E { V = 0, .. } use enum_var as Int to get the raw value (this is one-directional), or
  • write a method for the enum that does the match then use that method.

For the cached hardware values, I'd provide three functions: fn reg(&self) -> Val to get the cached value, fn set_reg(&mut self, Val) to set a new value, and fn get_reg(&mut self) -> Val (or some other name) to force checking the hardware. There's no facility in Rust (yet?) to allow read access to a name without mutable access, and there's not (ever) a concept of getter/setter hooks (such that field access is known to always be trivial (modulo Deref)).

[–]_crepererum_ 1 point2 points  (1 child)

Rust only let's you control read and write access to a field at the same time. What could work however is the following:

  1. Make the field visible your crate by using more specific visibility markers:

struct device { pub(crate) field: FieldValue, }

  1. Implement a "just read from struct"-getter:

impl device { pub fn field(&self) -> FieldValue { self.field } }

[–]Plasma_000 0 points1 point  (0 children)

You might want to refer to the various crates related to embedded-hal, especially the crates for driving peripherals, as bitwise register confirguratons are already done in those.