add proxmox-uuid crate

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2021-10-01 15:07:07 +02:00
parent 77dc52c047
commit bd67ccc1b3
9 changed files with 174 additions and 26 deletions

View File

@ -5,6 +5,7 @@ members = [
"proxmox-http",
"proxmox-sortable-macro",
"proxmox-tfa",
"proxmox-uuid",
]
exclude = [
"build",

View File

@ -5,7 +5,8 @@ CRATES = \
proxmox-api-macro \
proxmox-http \
proxmox-sortable-macro \
proxmox-tfa
proxmox-tfa \
proxmox-uuid
# By default we just run checks:
.PHONY: all

20
proxmox-uuid/Cargo.toml Normal file
View File

@ -0,0 +1,20 @@
[package]
name = "proxmox-uuid"
version = "1.0.0"
authors = ["Proxmox Support Team <support@proxmox.com>"]
edition = "2018"
license = "AGPL-3"
description = "bindings for libuuid with optional serde support"
exclude = [ "debian" ]
[dependencies]
libc = "0.2"
serde = { version = "1.0", optional = true }
[features]
default = []
[dev-dependencies]
serde = "1.0"
serde_json = "1.0"

View File

@ -0,0 +1,5 @@
rust-proxmox-uuid (1.0.0-1) stable; urgency=medium
* initial split out of `librust-proxmox-dev`
-- Proxmox Support Team <support@proxmox.com> Mon, 04 Oct 2021 11:38:53 +0200

View File

@ -0,0 +1,49 @@
Source: rust-proxmox-uuid
Section: rust
Priority: optional
Build-Depends: debhelper (>= 12),
dh-cargo (>= 24),
cargo:native <!nocheck>,
rustc:native <!nocheck>,
libstd-rust-dev <!nocheck>,
librust-libc-0.2+default-dev <!nocheck>
Maintainer: Proxmox Support Team <support@proxmox.com>
Standards-Version: 4.5.1
Vcs-Git: git://git.proxmox.com/git/proxmox.git
Vcs-Browser: https://git.proxmox.com/?p=proxmox.git
Rules-Requires-Root: no
Package: librust-proxmox-uuid-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-libc-0.2+default-dev
Suggests:
librust-proxmox-uuid+serde-dev (= ${binary:Version})
Provides:
librust-proxmox-uuid+default-dev (= ${binary:Version}),
librust-proxmox-uuid-1-dev (= ${binary:Version}),
librust-proxmox-uuid-1+default-dev (= ${binary:Version}),
librust-proxmox-uuid-1.0-dev (= ${binary:Version}),
librust-proxmox-uuid-1.0+default-dev (= ${binary:Version}),
librust-proxmox-uuid-1.0.0-dev (= ${binary:Version}),
librust-proxmox-uuid-1.0.0+default-dev (= ${binary:Version})
Description: Bindings for libuuid with optional serde support - Rust source code
This package contains the source for the Rust proxmox-uuid crate, packaged by
debcargo for use with cargo and dh-cargo.
Package: librust-proxmox-uuid+serde-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-proxmox-uuid-dev (= ${binary:Version}),
librust-serde-1+default-dev
Provides:
librust-proxmox-uuid-1+serde-dev (= ${binary:Version}),
librust-proxmox-uuid-1.0+serde-dev (= ${binary:Version}),
librust-proxmox-uuid-1.0.0+serde-dev (= ${binary:Version})
Description: Bindings for libuuid with optional serde support - feature "serde"
This metapackage enables feature "serde" for the Rust proxmox-uuid crate, by
pulling in any additional dependencies needed by that feature.

View File

@ -0,0 +1,16 @@
Copyright (C) 2021 Proxmox Server Solutions GmbH
This software is written by Proxmox Server Solutions GmbH <support@proxmox.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@ -0,0 +1,7 @@
overlay = "."
crate_src_path = ".."
maintainer = "Proxmox Support Team <support@proxmox.com>"
[source]
vcs_git = "git://git.proxmox.com/git/proxmox.git"
vcs_browser = "https://git.proxmox.com/?p=proxmox.git"

View File

@ -3,11 +3,6 @@
use std::borrow::{Borrow, BorrowMut};
use std::fmt;
use anyhow::{bail, Error};
use serde::{Serialize, Serializer};
use crate::tools::parse::hex_nibble;
#[link(name = "uuid")]
extern "C" {
fn uuid_generate(out: *mut [u8; 16]);
@ -15,10 +10,32 @@ extern "C" {
fn uuid_unparse_upper(input: *const [u8; 16], out: *mut u8);
}
/// An error parsing a uuid from a string.
#[derive(Debug, Clone, Copy)]
pub struct UuidError;
impl fmt::Display for UuidError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("bad uuid format")
}
}
impl std::error::Error for UuidError {}
/// Check for hex digits.
fn hex_digit(b: u8) -> Result<u8, UuidError> {
Ok(match b {
b'0'..=b'9' => b - b'0',
b'a'..=b'f' => b - b'a' + 0xA,
b'A'..=b'F' => b - b'A' + 0xA,
_ => return Err(UuidError),
})
}
/// Uuid generated with the system's native libuuid.
///
/// ```
/// use proxmox::tools::uuid::Uuid;
/// use proxmox_uuid::Uuid;
///
/// let uuid = Uuid::generate();
/// println!("Generated uuid: {}", uuid);
@ -58,7 +75,7 @@ impl Uuid {
/// Parse a uuid in optionally-hyphenated format.
///
/// ```
/// use proxmox::tools::uuid::Uuid;
/// use proxmox_uuid::Uuid;
///
/// let gen = Uuid::generate();
/// let text = format!("{}", gen);
@ -69,7 +86,7 @@ impl Uuid {
/// let uuid2: Uuid = "65b85639-78d7-4330-85c6-39502b2f9b01".parse().unwrap();
/// assert_eq!(uuid1, uuid2);
/// ```
pub fn parse_str(src: &str) -> Result<Self, Error> {
pub fn parse_str(src: &str) -> Result<Self, UuidError> {
use std::alloc::{alloc, Layout};
let uuid: *mut [u8; 16] = unsafe { alloc(Layout::new::<[u8; 16]>()) as *mut [u8; 16] };
if src.len() == 36 {
@ -78,31 +95,31 @@ impl Uuid {
let uuid: &mut [u8] = unsafe { &mut (*uuid)[..] };
let src = src.as_bytes();
if src[8] != b'-' || src[13] != b'-' || src[18] != b'-' || src[23] != b'-' {
bail!("failed to parse uuid");
return Err(UuidError);
}
for i in 0..4 {
uuid[i] = hex_nibble(src[2 * i])? << 4 | hex_nibble(src[2 * i + 1])?;
uuid[i] = hex_digit(src[2 * i])? << 4 | hex_digit(src[2 * i + 1])?;
}
for i in 4..6 {
uuid[i] = hex_nibble(src[2 * i + 1])? << 4 | hex_nibble(src[2 * i + 2])?;
uuid[i] = hex_digit(src[2 * i + 1])? << 4 | hex_digit(src[2 * i + 2])?;
}
for i in 6..8 {
uuid[i] = hex_nibble(src[2 * i + 2])? << 4 | hex_nibble(src[2 * i + 3])?;
uuid[i] = hex_digit(src[2 * i + 2])? << 4 | hex_digit(src[2 * i + 3])?;
}
for i in 8..10 {
uuid[i] = hex_nibble(src[2 * i + 3])? << 4 | hex_nibble(src[2 * i + 4])?;
uuid[i] = hex_digit(src[2 * i + 3])? << 4 | hex_digit(src[2 * i + 4])?;
}
for i in 10..16 {
uuid[i] = hex_nibble(src[2 * i + 4])? << 4 | hex_nibble(src[2 * i + 5])?;
uuid[i] = hex_digit(src[2 * i + 4])? << 4 | hex_digit(src[2 * i + 5])?;
}
} else if src.len() == 32 {
let uuid: &mut [u8] = unsafe { &mut (*uuid)[..] };
let src = src.as_bytes();
for i in 0..16 {
uuid[i] = hex_nibble(src[2 * i])? << 4 | hex_nibble(src[2 * i + 1])?;
uuid[i] = hex_digit(src[2 * i])? << 4 | hex_digit(src[2 * i + 1])?;
}
} else {
bail!("unrecognized uuid format");
return Err(UuidError);
}
Ok(Self(unsafe { Box::from_raw(uuid) }))
}
@ -185,17 +202,18 @@ impl fmt::UpperHex for Uuid {
}
impl std::str::FromStr for Uuid {
type Err = Error;
type Err = UuidError;
fn from_str(src: &str) -> Result<Self, Error> {
fn from_str(src: &str) -> Result<Self, UuidError> {
Self::parse_str(src)
}
}
impl Serialize for Uuid {
#[cfg(feature = "serde")]
impl serde::Serialize for Uuid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
S: serde::Serializer,
{
let mut buf = [0u8; 37];
unsafe {
@ -205,10 +223,45 @@ impl Serialize for Uuid {
}
}
forward_deserialize_to_from_str!(Uuid);
//forward_deserialize_to_from_str!(Uuid);
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Uuid {
fn deserialize<D>(deserializer: D) -> Result<Uuid, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
struct ForwardToStrVisitor;
impl<'a> serde::de::Visitor<'a> for ForwardToStrVisitor {
type Value = Uuid;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid uuid as a string")
}
fn visit_str<E: Error>(self, v: &str) -> Result<Uuid, E> {
v.parse::<Uuid>()
.map_err(|err| Error::custom(err.to_string()))
}
}
deserializer.deserialize_str(ForwardToStrVisitor)
}
}
#[test]
fn test_uuid() {
let uuid = Uuid::generate();
let ser: String = uuid.to_string();
let de: Uuid = ser.parse().expect("failed to parse uuid");
assert_eq!(uuid, de);
}
#[cfg(feature = "serde")]
#[test]
fn test_uuid_serde() {
let uuid = Uuid::generate();
let ser: String = serde_json::to_string(&uuid).expect("failed to serialize uuid");
let de: Uuid = serde_json::from_str(&ser).expect("failed to deserialize uuid");

View File

@ -18,13 +18,9 @@ pub mod mmap;
pub mod parse;
pub mod serde;
pub mod time;
pub mod uuid;
pub mod vec;
pub mod systemd;
#[doc(inline)]
pub use uuid::Uuid;
#[doc(inline)]
pub use as_any::AsAny;