Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From orphanage-0.1.4 To orphanage-0.2.0
2025-04-03
| ||
00:38 | Lossy cast. check-in: de2563a827 user: jan tags: trunk | |
2025-04-02
| ||
23:43 | Add change log section. check-in: e41a571187 user: jan tags: orphanage-0.2.0, trunk | |
23:40 | Release maintenance. check-in: 9678aea121 user: jan tags: trunk | |
2025-02-21
| ||
04:00 | Update rusqlite and rand. check-in: d9acfcb640 user: jan tags: trunk | |
2024-11-22
| ||
14:23 | Release maintenance. check-in: 2b23697533 user: jan tags: orphanage-0.1.4, trunk | |
14:21 | Add 'outdated' functions to fs module, useful for driving dependency rules. check-in: 89ac2f5207 user: jan tags: trunk | |
Changes to .efiles.
1 2 3 4 5 6 7 8 9 10 | Cargo.toml README.md www/index.md www/changelog.md src/err.rs src/lib.rs src/path.rs src/fs.rs src/strx.rs src/buf.rs | > < < > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | Cargo.toml README.md www/index.md www/changelog.md src/err.rs src/lib.rs src/path.rs src/fs.rs src/strx.rs src/numx.rs src/buf.rs src/futures.rs src/iox.rs src/tokiox.rs src/serde_parsers.rs src/setops.rs src/ffi.rs tests/setops.rs examples/fut_if_some.rs examples/deser.rs examples/slasher.rs examples/diskfree.rs |
Changes to Cargo.toml.
1 2 | [package] name = "orphanage" | | | 1 2 3 4 5 6 7 8 9 10 | [package] name = "orphanage" version = "0.2.0" edition = "2021" license = "0BSD" # https://crates.io/category_slugs categories = [ "network-programming" ] keywords = [ "sqlite", "fs", "path" ] repository = "https://repos.qrnch.tech/pub/orphanage" description = "Random collection of stuff that is still searching for a home." |
︙ | ︙ | |||
20 21 22 23 24 25 26 | ] # https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section [badges] maintenance = { status = "experimental" } [features] | | < | | < > | < | | > > > > > > > > > > > > | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | ] # https://doc.rust-lang.org/cargo/reference/manifest.html#the-badges-section [badges] maintenance = { status = "experimental" } [features] tokio = ["dep:tokio"] serde = ["dep:serde", "dep:parse-size"] [dependencies] #async-trait = { version = "0.1.86", optional = true } hashbrown = { version = "0.15.2" } parse-size = { version = "1.1.0", optional = true } paste = { version = "1.0.15" } rand = { version = "0.9.0" } serde = { version = "1.0.218", optional = true, features = ["derive"] } sha2 = { version = "0.10.8", optional = true } sha3 = { version = "0.10.8", optional = true } shellexpand = { version = "3.1.0" } tokio = { version = "1.41.0", optional = true, features = [ "macros", "net", "time" ] } [target.'cfg(unix)'.dependencies] libc = { version = "0.2.171" } [target.'cfg(windows)'.dependencies] windows-sys = { version = "0.59.0", features = [ "Win32_Foundation", "Win32_Storage", "Win32_Storage_FileSystem" ] } [dev-dependencies] humansize = { version = "2.1.3" } killswitch = { version = "0.4.2" } tokio = { version = "1.43.0", features = ["full"] } tokio-test = { version = "0.4.3" } toml = { version = "0.8.20" } [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] [lints.clippy] all = { level = "warn", priority = -1 } pedantic = { level = "warn", priority = -1 } nursery = { level = "warn", priority = -1 } cargo = { level = "warn", priority = -1 } multiple_crate_versions = "allow" |
Added examples/diskfree.rs.
> > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | use std::{env, path::Path}; use humansize::{format_size, BINARY, DECIMAL}; use orphanage::fs::get_free_space; fn main() { let pth = env::args_os().nth(1).expect("no pattern given"); let pth = Path::new(&pth); let freespace = get_free_space(pth).unwrap(); println!("{freespace}"); println!("{}", freespace / 1024); println!("{}", freespace / 1024 / 1024); let hs: String = format_size(freespace, DECIMAL); println!("{hs}"); let hs: String = format_size(freespace, BINARY); println!("{hs}"); } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/buf.rs.
︙ | ︙ | |||
11 12 13 14 15 16 17 | let mut buf = Vec::with_capacity(len); // SAFETY: Presumably with_capacity() works as documented. unsafe { buf.set_len(len); } | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 | let mut buf = Vec::with_capacity(len); // SAFETY: Presumably with_capacity() works as documented. unsafe { buf.set_len(len); } rand::rng().fill(&mut buf[..]); buf } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Added src/ffi.rs.
> > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | use std::{ffi::CString, path::Path}; /// Given a `Path`, return a `CString`, suitable for passing to C functions /// that require null-terminated paths. /// /// # Panics /// Path must not include null's (which they shouldn't be able to). #[must_use] #[inline] pub fn path_to_cstring(path: &Path) -> CString { let os_str = path.as_os_str(); let bytes = os_str.as_encoded_bytes(); // unwrap() should be okay because embeded null shouldn't be possible in a // Path. CString::new(bytes).unwrap() } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/fs.rs.
1 2 3 4 5 6 | use std::{ fs, io::ErrorKind, path::{Path, PathBuf} }; | > > | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | use std::{ fs, io::ErrorKind, path::{Path, PathBuf} }; #[cfg(windows)] use windows_sys::Win32::Storage::FileSystem::GetDiskFreeSpaceExA; use crate::{err::Error, ffi::path_to_cstring}; /// Create a random file of a specified size. /// /// # Errors /// [`std::io::Error`] pub fn rndfile( fname: impl AsRef<Path>, |
︙ | ︙ | |||
62 63 64 65 66 67 68 | pub fn abspath<P>(pth: P) -> Result<PathBuf, Error> where P: AsRef<Path> { Ok(pth.as_ref().canonicalize()?) } | < | 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | pub fn abspath<P>(pth: P) -> Result<PathBuf, Error> where P: AsRef<Path> { Ok(pth.as_ref().canonicalize()?) } /// Call a closure if `outfile` is outdated (according to the rules of /// [`outdated()`] with regards to `infile`. /// /// Returns `Ok(true)` if the closure was called. /// /// # Errors /// Errors mirror the behavior of [`outdated()`]'s errors. |
︙ | ︙ | |||
115 116 117 118 119 120 121 122 | let in_mtime = in_md.modified()?; let out_mtime = out_md.modified()?; Ok(in_mtime > out_mtime) } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | let in_mtime = in_md.modified()?; let out_mtime = out_md.modified()?; Ok(in_mtime > out_mtime) } /// Given a directory, return how much disk space is available. /// /// The directory must exist. /// /// # Errors /// [`Error::IO`] is returned if the input path is not a directory or if the /// free space could not be probed. pub fn get_free_space(path: &Path) -> Result<u64, Error> { #[cfg(unix)] let res = get_free_space_unix(path); #[cfg(windows)] let res = get_free_space_win(path); res } #[cfg(unix)] fn get_free_space_unix(path: &Path) -> Result<u64, Error> { // Make sure directory exists if !path.is_dir() { return Err(Error::IO("Not a directory".into())); } // Must construct a null-terminated C string for libc::statfs() let cstr = path_to_cstring(path); let cstr_path = cstr.as_bytes_with_nul(); let mut statfs = unsafe { std::mem::zeroed() }; let result = unsafe { libc::statfs(cstr_path.as_ptr().cast::<i8>(), &mut statfs) }; if result == 0 { Ok(statfs.f_bavail as u64 * u64::from(statfs.f_bsize)) } else { Err(Error::IO("statfs() failed".into())) } } #[cfg(windows)] fn get_free_space_win(path: &Path) -> Result<u64, Error> { // Make sure directory exists if !path.is_dir() { return Err(Error::IO("Not a directory".into())); } // Need a null-terminated string for ffi let cstr = path_to_cstring(path); let cstr_path = cstr.as_bytes_with_nul(); let mut free_bytes_available_to_caller: u64 = 0; let mut total_bytes: u64 = 0; let mut total_free_bytes: u64 = 0; let result = unsafe { GetDiskFreeSpaceExA( cstr_path.as_ptr(), &mut free_bytes_available_to_caller, &mut total_bytes, &mut total_free_bytes ) }; if result != 0 { Ok(free_bytes_available_to_caller) } else { Err(Error::IO(format!( "GetDiskFreeSpaceExW failed with code: {}", std::io::Error::last_os_error() ))) } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/iox.rs.
︙ | ︙ | |||
24 25 26 27 28 29 30 | if let Some(ref mut remain) = self.0 { if *remain == 0 { // signal eof Ok(0) } else { let n = std::cmp::min(*remain, buf.len() as u64); let len = usize::try_from(n).unwrap(); | | | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | if let Some(ref mut remain) = self.0 { if *remain == 0 { // signal eof Ok(0) } else { let n = std::cmp::min(*remain, buf.len() as u64); let len = usize::try_from(n).unwrap(); rand::rng().fill(&mut buf[..len]); *remain -= n; Ok(len) } } else { rand::rng().fill(&mut buf[..]); Ok(buf.len()) } } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/lib.rs.
1 2 3 4 5 6 7 8 9 10 11 | #![cfg_attr(docsrs, feature(doc_cfg))] pub mod buf; mod err; pub mod fs; pub mod futures; pub mod iox; pub mod path; pub mod setops; pub mod strx; | > > < < < < < < < < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | #![cfg_attr(docsrs, feature(doc_cfg))] pub mod buf; mod err; pub mod ffi; pub mod fs; pub mod futures; pub mod iox; pub mod numx; pub mod path; pub mod setops; pub mod strx; #[cfg(feature = "tokio")] #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))] pub mod tokiox; #[cfg(feature = "serde")] #[cfg_attr(docsrs, doc(cfg(feature = "serde")))] pub mod serde_parsers; pub use err::Error; // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Added src/numx.rs.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | use paste::paste; pub trait UnsignedExt { type Type; /// Round down integer to its closes power-of-two. fn round_down_to_pow2(self) -> Self::Type; /// Generate a vector of all bit indexes containing a `1`. fn bitidx_vec(self) -> Vec<usize>; } /// Given an array of (sorted) indexes, generate a vector of contiguous blocks. /// /// Each block is inclusive-inclusive. #[must_use] pub fn usize_list_to_ranges(numbers: &[usize]) -> Vec<(usize, usize)> { let mut result = Vec::with_capacity(numbers.len()); if numbers.is_empty() { return result; } let mut numbers_iter = numbers.iter().peekable(); while let Some(&num) = numbers_iter.next() { let start = num; let mut end = num; while let Some(&&next_num) = numbers_iter.peek() { if next_num == end + 1 { end = next_num; numbers_iter.next(); } else { break; } } if start == end { result.push((start, start)); } else { result.push((start, end)); } } result } #[must_use] pub fn ranges_to_str(blocks: &[(usize, usize)]) -> String { let mut res = String::new(); if blocks.is_empty() { return res; } let mut it = blocks.iter().peekable(); while let Some((start, end)) = it.next() { if start == end { res.push_str(&start.to_string()); } else { res.push_str(&format!("{start}-{end}")); } if it.peek().is_some() { res.push(','); } } res } macro_rules! impl_unsigned_ext { ($int_type:ident) => { paste! { #[must_use] pub const fn [<$int_type _round_down_to_pow2>](val: $int_type) -> $int_type { if val == 0 { return 0; } let n = val.leading_zeros(); let nshift = $int_type::BITS - n - 1; 1 << nshift } } paste! { #[must_use] pub fn [<$int_type _bitidx_vec>](bits: $int_type) -> Vec<usize> { let nbits = $int_type::BITS as usize; let mut ret = Vec::with_capacity(nbits); for idx in 0..nbits { if bits & (1 << idx) != 0 { ret.push(idx + 1); } } ret } } paste! { impl UnsignedExt for $int_type { type Type = $int_type; #[inline] fn round_down_to_pow2(self) -> Self::Type { [<$int_type _round_down_to_pow2>](self) } #[inline] fn bitidx_vec(self) -> Vec<usize> { [<$int_type _bitidx_vec>](self) } } } }; } impl_unsigned_ext! { u8 } impl_unsigned_ext! { u16 } impl_unsigned_ext! { u32 } impl_unsigned_ext! { u64 } impl_unsigned_ext! { usize } #[cfg(test)] mod tests { use super::*; #[test] fn bitidxvec() { let v = u32_bitidx_vec(0); assert_eq!(v.len(), 0); let v = u32_bitidx_vec(1); assert_eq!(&v, &[1]); let v = u32_bitidx_vec(2); assert_eq!(&v, &[2]); let v = u32_bitidx_vec(3); assert_eq!(&v, &[1, 2]); let v = u32_bitidx_vec(4); assert_eq!(&v, &[3]); } #[test] fn to_range_blocks() { let v = u32_bitidx_vec(0); let v2 = usize_list_to_ranges(&v); assert_eq!(v2.len(), 0); let v = u32_bitidx_vec(1); let v2 = usize_list_to_ranges(&v); assert_eq!(&v2, &[(1, 1)]); let v = u32_bitidx_vec(2); let v2 = usize_list_to_ranges(&v); assert_eq!(&v2, &[(2, 2)]); let v = u32_bitidx_vec(3); let v2 = usize_list_to_ranges(&v); assert_eq!(&v2, &[(1, 2)]); } #[test] fn to_ranges_str() { let v = u32_bitidx_vec(0); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert!(s.is_empty()); let v = u32_bitidx_vec(1); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert_eq!(&s, "1"); let v = u32_bitidx_vec(2); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert_eq!(&s, "2"); let v = u32_bitidx_vec(3); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert_eq!(&s, "1-2"); let v = u32_bitidx_vec(4); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert_eq!(&s, "3"); let v = u32_bitidx_vec(5); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert_eq!(&s, "1,3"); let v = u32_bitidx_vec(1 + 2 + 8 + 16); let v2 = usize_list_to_ranges(&v); let s = ranges_to_str(&v2); assert_eq!(&s, "1-2,4-5"); } #[test] fn round_down_to_pow2() { assert_eq!(u8::round_down_to_pow2(0), 0); assert_eq!(u8::round_down_to_pow2(1), 1); assert_eq!(u8::round_down_to_pow2(2), 2); assert_eq!(u8::round_down_to_pow2(3), 2); assert_eq!(u16::round_down_to_pow2(0), 0); assert_eq!(u16::round_down_to_pow2(1), 1); assert_eq!(u16::round_down_to_pow2(2), 2); assert_eq!(u16::round_down_to_pow2(3), 2); assert_eq!(u32::round_down_to_pow2(0), 0); assert_eq!(u32::round_down_to_pow2(1), 1); assert_eq!(u32::round_down_to_pow2(2), 2); assert_eq!(u32::round_down_to_pow2(3), 2); assert_eq!(u64::round_down_to_pow2(0), 0); assert_eq!(u64::round_down_to_pow2(1), 1); assert_eq!(u64::round_down_to_pow2(2), 2); assert_eq!(u64::round_down_to_pow2(3), 2); } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Deleted src/sqlfuncs.rs.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to src/strx.rs.
1 2 | //! Extended str/string functionality. | | < < | | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | //! Extended str/string functionality. use rand::{distr::Alphanumeric, Rng}; pub trait RndStr { fn rnd_alphanum(len: usize) -> String; fn rnd_from_alphabet(len: usize, alpha: &[u8]) -> String; } impl RndStr for String { /// Generate a random alphanumeric string of a requested length. fn rnd_alphanum(len: usize) -> String { rand::rng() .sample_iter(&Alphanumeric) .take(len) .map(char::from) .collect() } /// Generate a random string of a requested length, given an alphabet of /// acceptable characters. /// /// ``` /// use orphanage::strx::RndStr; /// /// const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\ /// abcdefghijklmnopqrstuvwxyz\ /// 0123456789-_"; /// /// let s = String::rnd_from_alphabet(16, CHARSET); /// assert_eq!(s.len(), 16); /// ``` fn rnd_from_alphabet(len: usize, charset: &[u8]) -> String { let mut rng = rand::rng(); (0..len) .map(|_| { let idx = rng.random_range(0..charset.len()); charset[idx] as char }) .collect() } } |
︙ | ︙ | |||
59 60 61 62 63 64 65 | pub const OBJNAME_SPEC: &str = "must be non-empty, lead with an alphabetic \ character, with each following character \ being alphanumeric, '_', '-' or '.'"; #[allow(clippy::missing_errors_doc)] | | < | < < | < | < < | | | 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | pub const OBJNAME_SPEC: &str = "must be non-empty, lead with an alphabetic \ character, with each following character \ being alphanumeric, '_', '-' or '.'"; #[allow(clippy::missing_errors_doc)] pub fn validate_name<L, R>(s: &str, lead: L, rest: R) -> Result<&str, String> where L: Fn(char) -> bool, R: Fn(char) -> bool { let mut chars = s.chars(); let Some(ch) = chars.next() else { return Err("must not be empty".into()); }; if !lead(ch) { return Err("invalid leading character".into()); } if chars.any(|c| !rest(c)) { return Err("invalid character".into()); } Ok(s) } #[inline] #[allow(clippy::missing_errors_doc)] pub fn validate_objname(s: &str) -> Result<&str, String> { validate_name(s, is_name_leading_char, is_name_char) } #[cfg(test)] mod tests { use super::*; |
︙ | ︙ |
Changes to src/tokiox.rs.
1 | //! tokio extensions. | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1 2 3 4 5 6 7 8 | //! tokio extensions. /// If a timeout has been specified, sleep until then. /// /// Otherwise wait forever. /// /// Can be used to timeout select loops. pub async fn sleep_until_if_some(at: Option<tokio::time::Instant>) { |
︙ | ︙ |
Deleted src/tokiox/tcpconn.rs.
|
| < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < |
Changes to www/changelog.md.
1 2 3 4 | # Change Log ## [Unreleased] | > > > > > > > > > > > > > > | > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | # Change Log ⚠️ indicates a breaking change. ## [Unreleased] [Details](/vdiff?from=orphanage-0.2.0&to=trunk) ### Added ### Changed ### Removed --- ## [0.2.0] - 2025-04-03 [Details](/vdiff?from=orphanage-0.1.4&to=orphanage-0.2.0) ### Added - Add `ffi` module with a `path_to_cstring()` function. ### Changed - Upgrade `rand` to `0.9.0`. - ⚠️ Change `validate_name()` and `validate_objname` to return `Result<(), String>` with a more constrained message. ### Removed - ⚠️ Removed `sqlfuncs` module (it lives in [sqlfuncs](https://crates.io/crates/sqlfuncs) now) - Removed rusqlite dependency (as a consequence of sqlfuncs being removed) - ⚠️ Remove `tokiox::{Connector, run_connector, tcpconn}`. The connector lives in [schmoozer](https://crates.io/crates/schmoozer) now. - ⚠️ Remove `aync_trait` dependency (it used to be re-exported). --- ## [0.1.4] - 2024-11-22 [Details](/vdiff?from=orphanage-0.1.3&to=orphanage-0.1.4) ### Added |
︙ | ︙ |
Changes to www/index.md.
︙ | ︙ | |||
15 16 17 18 19 20 21 | The crate's documentation uses automatically generated feature labels, which currently requires nightly featuers. To build the documentation locally use: ``` RUSTFLAGS="--cfg docsrs" RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features ``` | > > > > > > > | 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | The crate's documentation uses automatically generated feature labels, which currently requires nightly featuers. To build the documentation locally use: ``` RUSTFLAGS="--cfg docsrs" RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features ``` ## Change log The details of changes can always be found in the timeline, but for a high-level view of changes between released versions there's a manually maintained [Change Log](./changelog.md). |