Make rand and serde dependencies optional

This commit is contained in:
Jonas Platte 2020-04-17 12:52:53 +02:00
parent 025e298274
commit 76a5a487d2
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
12 changed files with 74 additions and 15 deletions

View File

@ -32,5 +32,6 @@ script:
cargo clippy --all-targets --all-features -- -D warnings cargo clippy --all-targets --all-features -- -D warnings
fi fi
- cargo build --verbose - cargo build --verbose
- cargo test --verbose - cargo test --no-default-features --verbose
- cargo test --all-features --verbose
if: "type != push OR (tag IS blank AND branch = master)" if: "type != push OR (tag IS blank AND branch = master)"

View File

@ -19,10 +19,14 @@ Breaking changes:
instead of `&url::Host` instead of `&url::Host`
* `Error::InvalidHost` has been renamed to `Error::InvalidServerName`, because it also covers errors * `Error::InvalidHost` has been renamed to `Error::InvalidServerName`, because it also covers errors
in the port, not just the host part section of the server name in the port, not just the host part section of the server name
* The random identifier generation functions (`Id::new`) are now only available if the `rand`
feature of this crate is enabled
Improvements: Improvements:
* Add support for historical uppercase MXIDs * Add support for historical uppercase MXIDs
* Made all dependencies optional
* `serde` is the only one that is enabled by default
# 0.14.1 # 0.14.1

View File

@ -12,10 +12,13 @@ repository = "https://github.com/ruma/ruma-identifiers"
version = "0.14.1" version = "0.14.1"
edition = "2018" edition = "2018"
[features]
default = ["serde"]
[dependencies] [dependencies]
diesel = { version = "1.4.4", optional = true } diesel = { version = "1.4.4", optional = true }
rand = "0.7.3" rand = { version = "0.7.3", optional = true }
serde = "1.0.106" serde = { version = "1.0.106", optional = true }
[dev-dependencies] [dev-dependencies]
serde_json = "1.0.51" serde_json = "1.0.51"

View File

@ -1,5 +1,6 @@
//! Matrix device identifiers. //! Matrix device identifiers.
#[cfg(feature = "rand")]
use crate::generate_localpart; use crate::generate_localpart;
/// A Matrix device ID. /// A Matrix device ID.
@ -9,11 +10,12 @@ use crate::generate_localpart;
pub type DeviceId = String; pub type DeviceId = String;
/// Generates a random `DeviceId`, suitable for assignment to a new device. /// Generates a random `DeviceId`, suitable for assignment to a new device.
#[cfg(feature = "rand")]
pub fn generate() -> DeviceId { pub fn generate() -> DeviceId {
generate_localpart(8) generate_localpart(8)
} }
#[cfg(test)] #[cfg(all(test, feature = "rand"))]
mod tests { mod tests {
use super::generate; use super::generate;

View File

@ -5,7 +5,7 @@ use std::{borrow::Cow, convert::TryFrom, num::NonZeroU8};
#[cfg(feature = "diesel")] #[cfg(feature = "diesel")]
use diesel::sql_types::Text; use diesel::sql_types::Text;
use crate::{error::Error, generate_localpart, is_valid_server_name, parse_id, validate_id}; use crate::{error::Error, parse_id, validate_id};
/// A Matrix event ID. /// A Matrix event ID.
/// ///
@ -55,7 +55,10 @@ impl EventId {
/// ///
/// Does not currently ever fail, but may fail in the future if the homeserver cannot be parsed /// Does not currently ever fail, but may fail in the future if the homeserver cannot be parsed
/// parsed as a valid host. /// parsed as a valid host.
#[cfg(feature = "rand")]
pub fn new(server_name: &str) -> Result<Self, Error> { pub fn new(server_name: &str) -> Result<Self, Error> {
use crate::{generate_localpart, is_valid_server_name};
if !is_valid_server_name(server_name) { if !is_valid_server_name(server_name) {
return Err(Error::InvalidServerName); return Err(Error::InvalidServerName);
} }
@ -121,6 +124,7 @@ common_impls!(EventId, "a Matrix event ID");
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "serde")]
use serde_json::{from_str, to_string}; use serde_json::{from_str, to_string};
use super::EventId; use super::EventId;
@ -156,6 +160,7 @@ mod tests {
) )
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn generate_random_valid_event_id() { fn generate_random_valid_event_id() {
let event_id = EventId::new("example.com").expect("Failed to generate EventId."); let event_id = EventId::new("example.com").expect("Failed to generate EventId.");
@ -165,11 +170,13 @@ mod tests {
assert_eq!(id_str.len(), 31); assert_eq!(id_str.len(), 31);
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn generate_random_invalid_event_id() { fn generate_random_invalid_event_id() {
assert!(EventId::new("").is_err()); assert!(EventId::new("").is_err());
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_original_event_id() { fn serialize_valid_original_event_id() {
assert_eq!( assert_eq!(
@ -181,6 +188,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_base64_event_id() { fn serialize_valid_base64_event_id() {
assert_eq!( assert_eq!(
@ -193,6 +201,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_url_safe_base64_event_id() { fn serialize_valid_url_safe_base64_event_id() {
assert_eq!( assert_eq!(
@ -205,6 +214,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_original_event_id() { fn deserialize_valid_original_event_id() {
assert_eq!( assert_eq!(
@ -214,6 +224,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_base64_event_id() { fn deserialize_valid_base64_event_id() {
assert_eq!( assert_eq!(
@ -224,6 +235,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_url_safe_base64_event_id() { fn deserialize_valid_url_safe_base64_event_id() {
assert_eq!( assert_eq!(

View File

@ -14,9 +14,9 @@
#[cfg_attr(feature = "diesel", macro_use)] #[cfg_attr(feature = "diesel", macro_use)]
extern crate diesel; extern crate diesel;
use std::{borrow::Cow, convert::TryFrom, num::NonZeroU8}; use std::num::NonZeroU8;
use rand::{distributions::Alphanumeric, thread_rng, Rng}; #[cfg(feature = "serde")]
use serde::de::{self, Deserialize as _, Deserializer, Unexpected}; use serde::de::{self, Deserialize as _, Deserializer, Unexpected};
#[doc(inline)] #[doc(inline)]
@ -51,9 +51,11 @@ const MAX_BYTES: usize = 255;
const MIN_CHARS: usize = 4; const MIN_CHARS: usize = 4;
/// Generates a random identifier localpart. /// Generates a random identifier localpart.
#[cfg(feature = "rand")]
fn generate_localpart(length: usize) -> String { fn generate_localpart(length: usize) -> String {
thread_rng() use rand::Rng as _;
.sample_iter(&Alphanumeric) rand::thread_rng()
.sample_iter(&rand::distributions::Alphanumeric)
.take(length) .take(length)
.collect() .collect()
} }
@ -95,12 +97,13 @@ fn parse_id(id: &str, valid_sigils: &[char]) -> Result<NonZeroU8, Error> {
/// Deserializes any type of id using the provided TryFrom implementation. /// Deserializes any type of id using the provided TryFrom implementation.
/// ///
/// This is a helper function to reduce the boilerplate of the Deserialize implementations. /// This is a helper function to reduce the boilerplate of the Deserialize implementations.
#[cfg(feature = "serde")]
fn deserialize_id<'de, D, T>(deserializer: D, expected_str: &str) -> Result<T, D::Error> fn deserialize_id<'de, D, T>(deserializer: D, expected_str: &str) -> Result<T, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
T: for<'a> TryFrom<&'a str>, T: for<'a> std::convert::TryFrom<&'a str>,
{ {
Cow::<'_, str>::deserialize(deserializer).and_then(|v| { std::borrow::Cow::<'_, str>::deserialize(deserializer).and_then(|v| {
T::try_from(&v).map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &expected_str)) T::try_from(&v).map_err(|_| de::Error::invalid_value(Unexpected::Str(&v), &expected_str))
}) })
} }

View File

@ -63,6 +63,7 @@ macro_rules! common_impls {
} }
} }
#[cfg(feature = "serde")]
impl ::serde::Serialize for $id { impl ::serde::Serialize for $id {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -72,6 +73,7 @@ macro_rules! common_impls {
} }
} }
#[cfg(feature = "serde")]
impl<'de> ::serde::Deserialize<'de> for $id { impl<'de> ::serde::Deserialize<'de> for $id {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where

View File

@ -62,6 +62,7 @@ common_impls!(RoomAliasId, "a Matrix room alias ID");
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "serde")]
use serde_json::{from_str, to_string}; use serde_json::{from_str, to_string};
use super::RoomAliasId; use super::RoomAliasId;
@ -77,6 +78,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_room_alias_id() { fn serialize_valid_room_alias_id() {
assert_eq!( assert_eq!(
@ -88,6 +90,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_room_alias_id() { fn deserialize_valid_room_alias_id() {
assert_eq!( assert_eq!(

View File

@ -5,7 +5,7 @@ use std::{borrow::Cow, convert::TryFrom, num::NonZeroU8};
#[cfg(feature = "diesel")] #[cfg(feature = "diesel")]
use diesel::sql_types::Text; use diesel::sql_types::Text;
use crate::{error::Error, generate_localpart, is_valid_server_name, parse_id}; use crate::{error::Error, parse_id};
/// A Matrix room ID. /// A Matrix room ID.
/// ///
@ -33,7 +33,10 @@ impl RoomId {
/// 18 random ASCII characters. /// 18 random ASCII characters.
/// ///
/// Fails if the given homeserver cannot be parsed as a valid host. /// Fails if the given homeserver cannot be parsed as a valid host.
#[cfg(feature = "rand")]
pub fn new(server_name: &str) -> Result<Self, Error> { pub fn new(server_name: &str) -> Result<Self, Error> {
use crate::{generate_localpart, is_valid_server_name};
if !is_valid_server_name(server_name) { if !is_valid_server_name(server_name) {
return Err(Error::InvalidServerName); return Err(Error::InvalidServerName);
} }
@ -79,6 +82,7 @@ common_impls!(RoomId, "a Matrix room ID");
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "serde")]
use serde_json::{from_str, to_string}; use serde_json::{from_str, to_string};
use super::RoomId; use super::RoomId;
@ -94,6 +98,7 @@ mod tests {
); );
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn generate_random_valid_room_id() { fn generate_random_valid_room_id() {
let room_id = RoomId::new("example.com").expect("Failed to generate RoomId."); let room_id = RoomId::new("example.com").expect("Failed to generate RoomId.");
@ -103,11 +108,13 @@ mod tests {
assert_eq!(id_str.len(), 31); assert_eq!(id_str.len(), 31);
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn generate_random_invalid_room_id() { fn generate_random_invalid_room_id() {
assert!(RoomId::new("").is_err()); assert!(RoomId::new("").is_err());
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_room_id() { fn serialize_valid_room_id() {
assert_eq!( assert_eq!(
@ -119,6 +126,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_room_id() { fn deserialize_valid_room_id() {
assert_eq!( assert_eq!(

View File

@ -93,6 +93,7 @@ common_impls!(RoomIdOrAliasId, "a Matrix room ID or room alias ID");
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "serde")]
use serde_json::{from_str, to_string}; use serde_json::{from_str, to_string};
use super::RoomIdOrAliasId; use super::RoomIdOrAliasId;
@ -126,6 +127,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_room_id_or_alias_id_with_a_room_alias_id() { fn serialize_valid_room_id_or_alias_id_with_a_room_alias_id() {
assert_eq!( assert_eq!(
@ -138,6 +140,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_room_id_or_alias_id_with_a_room_id() { fn serialize_valid_room_id_or_alias_id_with_a_room_id() {
assert_eq!( assert_eq!(
@ -150,6 +153,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_room_id_or_alias_id_with_a_room_alias_id() { fn deserialize_valid_room_id_or_alias_id_with_a_room_alias_id() {
assert_eq!( assert_eq!(
@ -159,6 +163,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_room_id_or_alias_id_with_a_room_id() { fn deserialize_valid_room_id_or_alias_id_with_a_room_id() {
assert_eq!( assert_eq!(

View File

@ -8,9 +8,10 @@ use std::{
#[cfg(feature = "diesel")] #[cfg(feature = "diesel")]
use diesel::sql_types::Text; use diesel::sql_types::Text;
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::{deserialize_id, error::Error}; use crate::error::Error;
/// Room version identifiers cannot be more than 32 code points. /// Room version identifiers cannot be more than 32 code points.
const MAX_CODE_POINTS: usize = 32; const MAX_CODE_POINTS: usize = 32;
@ -155,6 +156,7 @@ impl Display for RoomVersionId {
} }
} }
#[cfg(feature = "serde")]
impl Serialize for RoomVersionId { impl Serialize for RoomVersionId {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
@ -164,12 +166,13 @@ impl Serialize for RoomVersionId {
} }
} }
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for RoomVersionId { impl<'de> Deserialize<'de> for RoomVersionId {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
deserialize_id(deserializer, "a Matrix room version ID as a string") crate::deserialize_id(deserializer, "a Matrix room version ID as a string")
} }
} }
@ -243,6 +246,7 @@ impl PartialEq<RoomVersionId> for String {
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "serde")]
use serde_json::{from_str, to_string}; use serde_json::{from_str, to_string};
use super::RoomVersionId; use super::RoomVersionId;
@ -324,6 +328,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_official_room_id() { fn serialize_official_room_id() {
assert_eq!( assert_eq!(
@ -333,6 +338,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_official_room_id() { fn deserialize_official_room_id() {
let deserialized = let deserialized =
@ -347,6 +353,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_custom_room_id() { fn serialize_custom_room_id() {
assert_eq!( assert_eq!(
@ -358,6 +365,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_custom_room_id() { fn deserialize_custom_room_id() {
let deserialized = from_str::<RoomVersionId>(r#""io.ruma.1""#) let deserialized = from_str::<RoomVersionId>(r#""io.ruma.1""#)

View File

@ -5,7 +5,7 @@ use std::{borrow::Cow, convert::TryFrom, num::NonZeroU8};
#[cfg(feature = "diesel")] #[cfg(feature = "diesel")]
use diesel::sql_types::Text; use diesel::sql_types::Text;
use crate::{error::Error, generate_localpart, is_valid_server_name, parse_id}; use crate::{error::Error, parse_id};
/// A Matrix user ID. /// A Matrix user ID.
/// ///
@ -39,7 +39,10 @@ impl UserId {
/// 12 random ASCII characters. /// 12 random ASCII characters.
/// ///
/// Fails if the given homeserver cannot be parsed as a valid host. /// Fails if the given homeserver cannot be parsed as a valid host.
#[cfg(feature = "rand")]
pub fn new(server_name: &str) -> Result<Self, Error> { pub fn new(server_name: &str) -> Result<Self, Error> {
use crate::{generate_localpart, is_valid_server_name};
if !is_valid_server_name(server_name) { if !is_valid_server_name(server_name) {
return Err(Error::InvalidServerName); return Err(Error::InvalidServerName);
} }
@ -108,6 +111,7 @@ common_impls!(UserId, "a Matrix user ID");
mod tests { mod tests {
use std::convert::TryFrom; use std::convert::TryFrom;
#[cfg(feature = "serde")]
use serde_json::{from_str, to_string}; use serde_json::{from_str, to_string};
use super::UserId; use super::UserId;
@ -134,6 +138,7 @@ mod tests {
assert!(user_id.is_historical()); assert!(user_id.is_historical());
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn generate_random_valid_user_id() { fn generate_random_valid_user_id() {
let user_id = UserId::new("example.com").expect("Failed to generate UserId."); let user_id = UserId::new("example.com").expect("Failed to generate UserId.");
@ -146,11 +151,13 @@ mod tests {
assert_eq!(id_str.len(), 25); assert_eq!(id_str.len(), 25);
} }
#[cfg(feature = "rand")]
#[test] #[test]
fn generate_random_invalid_user_id() { fn generate_random_invalid_user_id() {
assert!(UserId::new("").is_err()); assert!(UserId::new("").is_err());
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn serialize_valid_user_id() { fn serialize_valid_user_id() {
assert_eq!( assert_eq!(
@ -160,6 +167,7 @@ mod tests {
); );
} }
#[cfg(feature = "serde")]
#[test] #[test]
fn deserialize_valid_user_id() { fn deserialize_valid_user_id() {
assert_eq!( assert_eq!(