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

zbus 4.0 port #155

Merged
merged 17 commits into from
Mar 1, 2024
Merged

zbus 4.0 port #155

merged 17 commits into from
Mar 1, 2024

Conversation

TTWNO
Copy link
Member

@TTWNO TTWNO commented Feb 16, 2024

Good work so far, Luuk!

I'm just opening this so we can catalogue some of the issues we've had porting.

( Addresses #154 )

@TTWNO
Copy link
Member Author

TTWNO commented Feb 16, 2024

I needed explicit type annotations to compile on stable. Unsure if you've had the same issues.

It seems the bus is getting timed out... But I can't find the reason immediately.

@DataTriny
Copy link
Collaborator

Hello there,

We should of course upgrade to zbus 4 at some point, but now is way too soon for AccessKit. We just bumped our MSRV to 1.68 so I wouldn't want to be stuck on the current version of this crate for a while because of that.

@TTWNO
Copy link
Member Author

TTWNO commented Feb 16, 2024

We should of course upgrade to zbus 4 at some point, but now is way too soon for AccessKit.

No problem. Totally understand. I'll make a release right before we merge this so that you have everything we do up to but not including the zbus version upgrade.

Hope that is ok?

@DataTriny
Copy link
Collaborator

@TTWNO It all depends on when this will be ready and if I find things to add or fix here in the meantime.

I guess we'll all have to agree on how and when to bump our MSRV in sync at some point.

@luukvanderduim
Copy link
Collaborator

I understand you cannot bump MSVR now, however we do want to move on.
Zbus 4 offers a number of improvements we would like to leverage / benefit from.

For the time being AccessKit could depend on the atspi version you are currently on.
I believe AccessKit depends on atspi (mostly) for types doesn't it?

I have been pondering if a types-and-traits crate in the workspace could be something worth exploring.

@TTWNO
Copy link
Member Author

TTWNO commented Feb 17, 2024

I have been pondering if a types-and-traits crate in the workspace could be something worth exploring.

Would this just be atspi-common?

Copy link

codecov bot commented Feb 17, 2024

Codecov Report

Attention: Patch coverage is 73.24841% with 84 lines in your changes are missing coverage. Please review.

Project coverage is 88.97%. Comparing base (06c7d7e) to head (b72fe73).
Report is 9 commits behind head on main.

Files Patch % Lines
atspi-common/src/events/mod.rs 53.73% 31 Missing ⚠️
atspi-common/src/events/object.rs 70.37% 24 Missing ⚠️
atspi-proxies/src/accessible.rs 0.00% 6 Missing ⚠️
atspi-connection/src/lib.rs 57.14% 3 Missing ⚠️
atspi-common/src/error.rs 0.00% 1 Missing ⚠️
atspi-proxies/src/action.rs 0.00% 1 Missing ⚠️
atspi-proxies/src/application.rs 0.00% 1 Missing ⚠️
atspi-proxies/src/bus.rs 50.00% 1 Missing ⚠️
atspi-proxies/src/cache.rs 0.00% 1 Missing ⚠️
atspi-proxies/src/collection.rs 0.00% 1 Missing ⚠️
... and 14 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #155      +/-   ##
==========================================
- Coverage   89.97%   88.97%   -1.01%     
==========================================
  Files          39       39              
  Lines        3173     3228      +55     
==========================================
+ Hits         2855     2872      +17     
- Misses        318      356      +38     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@luukvanderduim
Copy link
Collaborator

I have been pondering if a types-and-traits crate in the workspace could be something worth exploring.

Would this just be atspi-common?

That would make things easier if we could..

Let's see:

  • zbus is an optional dependency on atspi-common, so that may work.
  • However, since zbus is a dependency (albeit being optional) we do have an MSRV.
  • Maybe if we remove the 'rust-version' key in this crate's Cargo.toml we could avoid forcing downstream users of the types into a new(er) rust version - as long as they do not enable zbus?

Then we'd need to carefully look at which types and traits we need to move over still.

@TTWNO
Copy link
Member Author

TTWNO commented Feb 21, 2024

Then we'd need to carefully look at which types and traits we need to move over still.

This sounds like more things to keep straight in our heads. Personally, I don't think that's a good idea.

@@ -131,7 +103,7 @@ impl Default for EventBodyQT {
/// Standard event body (GTK, `egui`, etc.)
/// NOTE: Qt has its own signature: [`EventBodyQT`].
/// Signature `(siiva{sv})`,
#[derive(Clone, Debug, Serialize, Deserialize, Type, PartialEq)]
#[derive(Debug, Serialize, Deserialize, Type, PartialEq)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was the Clone derive removed here?

Copy link
Collaborator

@luukvanderduim luukvanderduim Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EventBodyOwned has fields of type OwnedValue.
In zvariant 4, Values no longer have Clone because of the safe Fd work. Cloning is now achieved through Value::try_clone.

I manually re-implemented Clone using OwnedValue::try_clone to not break our API, because:

  • Suddenly missing Clone is pretty rough.
  • There is only a remote chance that we will hit the error path in this context, because it requires the current process to exceed the maximum number of open files: (from Value::try_clone docs)
Errors

This method can currently only fail on Unix platforms for [Value::Fd](https://docs.rs/zvariant/latest/zvariant/enum.Value.html#variant.Fd) variant containing an [Fd::Owned](https://docs.rs/zvariant/latest/zvariant/enum.Fd.html#variant.Owned) variant. This happens when the current process exceeds the maximum number of open file descriptors.

[edit: updated safe Fd work link.]

properties: HashMap::new(),
}
}
}

// Manual implementation to account for the remote chance that either `any_data` or `properties`
// fail to clone because the clone would exceed the open file limit.
impl Clone for EventBodyOwned {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see... Makes sense now.

}
}
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we just let the users of atspi call .try_clone() instead? And let them decide whether or not to fail?

Copy link
Collaborator

@luukvanderduim luukvanderduim Feb 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to 'lust be practical' considering the context:

Did or will EventBodyOwned.any_data ever contain a file?
Did or will EventBodyOwned.properties ever contain a file?

I don't think so and I think the chances are slim they ever will and should they ever, the chances of triggering the failure path are slim.

It is expected that a type has Clone.

let qt_body = body.deserialize::<EventBodyQT>()?;
Ok(EventBodyOwned::from(qt_body))
} else if signature == ATSPI_EVENT_SIGNATURE {
Ok(body.deserialize::<EventBodyOwned>()?)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test so that all three cases are covered (QT is currently not).

let with_parentheses = &Signature::from_static_str_unchecked("((ii)(ii))");
let without_parentheses = &Signature::from_static_str_unchecked("((((ii)(ii))))");
assert!(!signatures_are_eq(with_parentheses, without_parentheses));
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad to see this logic upstreamed.

property.clone(),
value.try_clone().unwrap_or_else(|err| {
eprintln!("Failed to clone value: {err:?}");
u8::default().into()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I would argue that we should give the .try_clone() option to users and let them handle errors.

On the other hand, it's not a trait (in std anyways), and it is exceedingly rare that this would actually be triggered.... Hmmmm

Does cloning a file descriptor do anything? Wouldn't the "limit" only be exceeded if we tried to open it?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIU, having the OwnedFd is having an open file, otherwise cloning these would not be limited?

I fully agree that the chances are slim. Have we ever seen file descriptors being sent?
If we can, I would like to not burden our users with try_clone() but just keep a Clone implementation.

atspi-proxies/Cargo.toml Show resolved Hide resolved
@DataTriny
Copy link
Collaborator

DataTriny commented Feb 21, 2024

@TTWNO Do you need cargo msrv in the first place?

I recently enforced MSRV for AccessKit:

  • I defined the Rust version once in the workspace manifest: rust-version = "1.68.2",
  • I made all members inherit the property: rust-version.workspace = true,
  • In the CI I used sed to grab the version defined on the workspace: echo "version=``cat Cargo.toml | sed -n 's/rust-version = "\(.*\)"/\1/p'``" >> "$GITHUB_OUTPUT",
  • And in the test jobs I installed Rust, specifying the version:
      - name: install stable toolchain
        uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ needs.find-msrv.outputs.version }}

If your CI fail with compile errors, then you know you broke your MSRV policy. It's usually enough since you also have a clippy job able to catch regular compile errors, should there be some. You might lose a bit of efficiency since you won't reuse the cache of the clippy job in the test jobs, not a big deal IMO.

@zeenix
Copy link

zeenix commented Feb 22, 2024

I guess we'll all have to agree on how and when to bump our MSRV in sync at some point.

I think it would be a good idea to have some (even vague) policy about it. Just for the record, I bumped MSRV in zbus to latest of the time only because it was a major version bump. I will be a lot more reluctant to bump it going forward until the next API break.

@TTWNO TTWNO changed the title Zbus4 port zbus 4.0 port Feb 22, 2024
@TTWNO
Copy link
Member Author

TTWNO commented Feb 22, 2024

@DataTriny great idea! I'll try that today and commit it.

@luukvanderduim
Copy link
Collaborator

luukvanderduim commented Feb 23, 2024

I think it would be a good idea to have some (even vague) policy about it. Just for the record, I bumped MSRV in zbus to latest of the time only because it was a major version bump. I will be a lot more reluctant to bump it going forward until the next API break.

@zeenix Do you have something in mind?

There is of course versioning policy: Considering we are <v1.0.0 and atspi is still a mess, breakage is to be expected.
That being said, I am open to catering AccessKit's needs by moving the AT-SPI2 types into a sub-crate without msrv.
Would that help you @DataTriny ?

@zeenix
Copy link

zeenix commented Feb 23, 2024

@zeenix Do you have something in mind?

It depends entirely on the maintainers according to the project's needs and I don't have enough context to suggest something specific. My suggestion was only that there should be policy (even if vague). In zbus, I'd try my best to not bump MSRV to anything newer than 6 months in a non-major release.

@DataTriny
Copy link
Collaborator

@luukvanderduim atspi-common would still have to depend on zvariant and zvariant-derive. But in AccessKit we use some proxies from atspi-proxies to grab the bus address and talk to the registry anyway. So it wouldn't help much.

I'd be curious to know what features you absolutely need from zbus 4.0 right now.

@luukvanderduim
Copy link
Collaborator

@luukvanderduim atspi-common would still have to depend on zvariant and zvariant-derive. But in AccessKit we use some proxies from atspi-proxies to grab the bus address and talk to the registry anyway. So it wouldn't help much.

You would be using atspi-connection for the bus address and atspi-proxies for the registry proxy. Nice to hear you're using those.

I'd be curious to know what features you absolutely need from zbus 4.0 right now.

@TTWNO
Copy link
Member Author

TTWNO commented Feb 29, 2024

@luukvanderduim

Ok, I'm coming around to your point on the Clone implementation. I've added a safety comment locally that links to zvariant::OwnedValue for more info.

However, I see there are a couple places where if you can not try_clone() correctly, instead of panicing, you use a default value:

  • atspi-common/src/events/object.rs:135
  • atspi-common/src/events/object.rs:235

Should these not also panic? I want to have consistent behaviour for library users. Even if that does mean that it can technically panic in more places.

@TTWNO
Copy link
Member Author

TTWNO commented Feb 29, 2024

Or, would you argue, like in ./atspi-common/src/events/object.rs:1239 that the comment is simply unnecessary due to the remoteness of the issue? Sorry if we're covering old ground, it's late here.

TTWNO and others added 7 commits February 28, 2024 22:59
```Rust
	loop {
		let to = events.try_next().await;
		let event = to
			.expect("stream timed out")
			.expect("stream closed")
			.expect("conversion to `Event` failed");

		if let Event::Cache(CacheEvents::Remove(event)) = event {
			let ObjectRef { name, path } = event.node_removed;
			assert_eq!(name.as_str(), ":69.420");
			assert_eq!(path.as_str(), "/org/a11y/atspi/accessible/remove");
		}
	}

```

In the above pattern we could receive our synthetic signal, but the loop would
carry on until the stream would timeout - or until an unrelated `Cache` event
would be received.

A simple `break;` fixes this.

Secondly to prevent unrelated `Cache` events from triggering our event assertions,
we now check whether the event sender name corresponds our connections' unique
name.
Since zvariant 4's changes on `Signature as PartialEq::eq` changes, `assert_eq!`
is now sufficient.
@TTWNO
Copy link
Member Author

TTWNO commented Mar 1, 2024

@DataTriny I've released atspi v0.21.0 with the latest changes (pre merging this branch). I've kept the same MSRV, dependencies (I think we even removed one), and especially zbus version.

Any future additions to the crate will be gated behind zbus 4.x.

@DataTriny
Copy link
Collaborator

Understood @TTWNO, thank you. All of this is very unfortunate...

@TTWNO
Copy link
Member Author

TTWNO commented Mar 1, 2024

All of this is very unfortunate...

I don't see the problem here? accesskit is often 6 months or so behind the latest version anyways; is there a reason you need us to keep compatibility with zbus 3.x for that long?

Or is there some other issue I'm not seeing here?

@zeenix
Copy link

zeenix commented Mar 1, 2024

Maybe the README is outdated but given the beta status of this project, I don't really see why bumping MSRV is a big problem here. 🤔

@DataTriny
Copy link
Collaborator

I just don't want to propose bumping AccessKit's MSRV to 1.75 before our biggest downstream users bring the subject, namely egui (currently on Rust 1.72) and slint (currently on Rust 1.70).

@TTWNO
Copy link
Member Author

TTWNO commented Mar 1, 2024

I just don't want to propose bumping AccessKit's MSRV to 1.75 before our biggest downstream users bring the subject,

Then don't. It's ok. Like I said, I often see accesskit being many months behind the latest atspi version. Accesskit's dependence on us has been really mostly the most fundemental types. Those aren't likely to change in the near futute.

I see no problem bumping this project, even if accesskit is not ready to.

On line object.rs:135

We no longer return a default but panic with helpful message.

On line object.rs:235

In this conversion, there are only `Strings` and a single `OwnedValue`,
which, at the end is just handed over and does not need to be cloned.
We should never see that `expect()` message.
- A few items needed backticks.
- An unneeded import.
@TTWNO TTWNO merged commit 8db6cd2 into main Mar 1, 2024
12 of 14 checks passed
@TTWNO TTWNO deleted the zbus4-port branch March 1, 2024 21:27
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

Successfully merging this pull request may close these issues.

4 participants