Skip to content

RUST-765 Ensure API meets Rust API guidelines #255

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

Merged
merged 10 commits into from
May 13, 2021

Conversation

patrickfreed
Copy link
Contributor

@patrickfreed patrickfreed commented May 10, 2021

RUST-765 / RUST-789 / RUST-788 / RUST-739

This PR makes a number of breaking changes to the API to ensure it meets the Rust API Guidelines checklist.

Notable changes:

  • Restructured or eliminated public dependencies on unstable crates to be compatible with future major releases of those crates
    • chrono:
      • Bson::DateTime(chrono::DateTime<Utc>) => Bson::DateTime(crate::DateTime)
      • removed pub from the wrapped chrono::DateTime in bson::DateTime
      • serde_helpers::chrono_datetime_as_bson_datetime => serde_helpers::chrono_0_4_datetime_as_bson_datetime
      • ObjectId::timestamp now returns a crate::DateTime
    • uuid:
      • serde_helpers::uuid_as_binary => serde_helpers::uuid_0_8_as_binary
    • hex: rewrote oid::Error to exclude it
  • All Document getters now accept impl AsRef<str> instead of &str
  • Updated ObjectId's constructors to match the names of uuid::Uuid
  • Attempting to serialize a DateTime with sub-millisecond precision to BSON data will result in an error
  • Renamed error variants to be less redundant and more consistent
    • de::Error:
      • Error:Io(...) => Error::Io(...)
      • Error::FromUtf8Error(...) => Error::InvalidUtf8String(...)
      • Error::SyntaxError removed, replaced by Error::DeserializationError
    • ser::Error:
      • Error::IoError(...) => Error::Io(...)

@patrickfreed patrickfreed marked this pull request as ready for review May 10, 2021 23:50
Utc.timestamp(num_secs, num_millis as u32 * 1_000_000)
.into()
impl crate::DateTime {
pub(crate) fn from_millis(date: i64) -> Self {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought about making this public, but apparently too-large values here can cause panics (RUST-799), so I just left it private for now until we decide how / if we want to tackle this publicly.

impl From<chrono::DateTime<Utc>> for DateTime {
fn from(x: chrono::DateTime<Utc>) -> Self {
DateTime(x)
impl<T: chrono::TimeZone> From<chrono::DateTime<T>> for crate::DateTime {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I updated this to be more general since it could be a little annoying to convert from DateTimes with other timezones otherwise.

/// pub id: Uuid,
/// }
/// ```
pub mod uuid_as_binary {
pub mod uuid_0_8_as_binary {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that with #239, each major version of uuid will come with 4 serde helper modules, which will pollute the namespace a bit. That doesn't seem too bad to me but we could consider gating it behind a feature flag if we want to avoid that.

Copy link

Choose a reason for hiding this comment

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

I don't feel very strongly either way

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I don't think that's a huge deal, I'm fine leaving as-is.

@patrickfreed
Copy link
Contributor Author

In light of our decision in mongodb/mongo-rust-driver#337 to drop the Error suffix from our error variants, I updated BSON's errors similarly.

Copy link

@kmahar kmahar left a comment

Choose a reason for hiding this comment

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

all seems pretty good, just some minor questions/comments

/// pub id: Uuid,
/// }
/// ```
pub mod uuid_as_binary {
pub mod uuid_0_8_as_binary {
Copy link

Choose a reason for hiding this comment

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

I don't feel very strongly either way

src/bson.rs Outdated
///
/// Just a helper for convenience
/// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
/// BSON datetime rather than an ISO-8601 formatted string. This means that it will serialize to and
Copy link

Choose a reason for hiding this comment

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

what does encoding as an extended JSON object entail in a non-BSON, non-extended JSON format? using the extJSON key names?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, so the way the crate implemented Serialize / Deserialize for the various types was to do BSON in BSON and extended JSON (or its equivalent) for all other serialization formats (This is something I suggested we try in Swift a while back). Users have expressed a decent amount of frustration around this (particularly around DateTime), though the serde helpers have helped a lot. I added this comment in here to further help clarify the situation, though I agree that part is a bit confusing. Updated the wording to be a bit more specific.

Given that we're breaking API, we could consider changing this approach, though I think that would probably require a lot of work. We could additively support alternate default serialization formats in the future via feature flags too, so it's not completely necessary to do it now.

Copy link

Choose a reason for hiding this comment

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

ah I see. yeah, I don't think we should try to tackle this now given there are ways to work around it, but seems like something good to keep in mind for the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filed RUST-801.

src/bson.rs Outdated
///
/// Just a helper for convenience
/// This type differs from [`chrono::DateTime`] in that it serializes to and deserializes from a
/// BSON datetime rather than an ISO-8601 formatted string. This means that it will serialize to and
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep, so the way the crate implemented Serialize / Deserialize for the various types was to do BSON in BSON and extended JSON (or its equivalent) for all other serialization formats (This is something I suggested we try in Swift a while back). Users have expressed a decent amount of frustration around this (particularly around DateTime), though the serde helpers have helped a lot. I added this comment in here to further help clarify the situation, though I agree that part is a bit confusing. Updated the wording to be a bit more specific.

Given that we're breaking API, we could consider changing this approach, though I think that would probably require a lot of work. We could additively support alternate default serialization formats in the future via feature flags too, so it's not completely necessary to do it now.

@@ -17,6 +17,9 @@ pub enum Error {
key: Bson,
},

/// Attempted to serialize a sub-millisecond precision datetime.
SubMillisecondPrecisionDateTime(crate::DateTime),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this error name seem okay? it's a little verbose but I couldn't come up with anything much better.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it's a little lengthy but I think it's fine

Copy link

Choose a reason for hiding this comment

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

agree it's fine. might be worth expanding the comment a little to clarify why that's an error though, e.g. adding "...which BSON does not support" or something like that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea, added.

@@ -500,14 +508,14 @@ impl Document {
}

/// Attempts to serialize the `Document` into a byte stream.
pub fn to_writer<W: Write + ?Sized>(&self, writer: &mut W) -> crate::ser::Result<()> {
pub fn to_writer<W: Write>(&self, mut writer: W) -> crate::ser::Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the reasoning behind this change?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is in line with the C-RW-VALUE guideline. Though it does mention to document this change, so I updated the docstring to contain some explanation and an example.

}

/// Constructs a new ObjectId wrapper around the raw byte representation.
pub fn with_bytes(bytes: [u8; 12]) -> ObjectId {
pub const fn from_bytes(bytes: [u8; 12]) -> ObjectId {
Copy link
Contributor

Choose a reason for hiding this comment

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

TIL Rust has const functions. Is this suggested as part of the API guidelines?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope, though there probably should be some mention of it there. I think it was quite limited for a while, but each release of Rust adds more things that can be done in const. In this case, I used it to match uuid::Uuid::from_bytes.

@@ -17,6 +17,9 @@ pub enum Error {
key: Bson,
},

/// Attempted to serialize a sub-millisecond precision datetime.
SubMillisecondPrecisionDateTime(crate::DateTime),
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it's a little lengthy but I think it's fine

/// pub id: Uuid,
/// }
/// ```
pub mod uuid_as_binary {
pub mod uuid_0_8_as_binary {
Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I don't think that's a huge deal, I'm fine leaving as-is.

Copy link

@kmahar kmahar left a comment

Choose a reason for hiding this comment

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

couple minor comments (sorry I screwed up and forgot to batch...) but don't need to re-review, lgtm

@kmahar
Copy link

kmahar commented May 12, 2021

oh and extremely small nit, in your PR title (which I think will become the commit message by default?): "guideliness" -> "guidelines"

@patrickfreed patrickfreed changed the title RUST-765 Ensure API meets Rust API guideliness RUST-765 Ensure API meets Rust API guidelines May 12, 2021
@patrickfreed patrickfreed force-pushed the RUST-765/api-guidelines branch from 4a52ec0 to 6ae63bc Compare May 12, 2021 22:18
@patrickfreed patrickfreed merged commit 097fbe5 into mongodb:master May 13, 2021
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.

3 participants