Skip to content

Commit 9aba129

Browse files
committed
integrate timestamp service
1 parent 1e6322b commit 9aba129

File tree

12 files changed

+75
-18
lines changed

12 files changed

+75
-18
lines changed

linkml-service/src/cli/stress_test.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Real stress testing implementation for `LinkML` CLI
22
3+
use crate::utils::safe_cast::f64_to_usize_saturating;
34
use rand::Rng;
45
use serde::{Deserialize, Serialize};
56
use serde_json::Value;
@@ -378,7 +379,7 @@ where
378379
return 0.0;
379380
}
380381

381-
let index = ((sorted_latencies.len() - 1) as f64 * percentile) as usize;
382+
let index = f64_to_usize_saturating((sorted_latencies.len() - 1) as f64 * percentile);
382383
sorted_latencies
383384
.get(index)
384385
.map_or(0.0, |d| d.as_millis() as f64)

linkml-service/src/generator/excel.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//! - Rich formatting options
1313
1414
use super::traits::{Generator, GeneratorError, GeneratorResult};
15+
use crate::utils::safe_cast::usize_to_f64;
1516
use async_trait::async_trait;
1617
use linkml_core::prelude::*;
1718
use rust_xlsxwriter::{
@@ -803,7 +804,7 @@ impl ExcelGenerator {
803804
match slot.range.as_deref() {
804805
Some("string") => format!("{} {}", name, index + 1),
805806
Some("integer") => format!("{}", (index + 1) * 10),
806-
Some("float") => format!("{:.2}", (index + 1) as f64 * 3.14),
807+
Some("float") => format!("{:.2}", usize_to_f64(index + 1) * 3.14),
807808
Some("boolean") => if index % 2 == 0 { "TRUE" } else { "FALSE" }.to_string(),
808809
Some("date") => format!("2024-01-{:02}", index + 1),
809810
Some("datetime") => format!("2024-01-{:02}T10:00:00", index + 1),

linkml-service/src/generator/java.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! This module generates Java classes from `LinkML` schemas with full
44
//! validation support and builder patterns.
55
6+
use crate::utils::safe_cast::f64_to_i64_saturating;
67
use linkml_core::{
78
error::LinkMLError,
89
types::{ClassDefinition, EnumDefinition, PermissibleValue, SchemaDefinition, SlotDefinition}};
@@ -272,13 +273,13 @@ impl JavaGenerator {
272273

273274
if let Some(min) = &slot.minimum_value
274275
&& let Some(num) = min.as_f64() {
275-
writeln!(output, " @Min({})", num as i64)
276+
writeln!(output, " @Min({})", f64_to_i64_saturating(num))
276277
.map_err(Self::fmt_error_to_generator_error)?;
277278
}
278279

279280
if let Some(max) = &slot.maximum_value
280281
&& let Some(num) = max.as_f64() {
281-
writeln!(output, " @Max({})", num as i64)
282+
writeln!(output, " @Max({})", f64_to_i64_saturating(num))
282283
.map_err(Self::fmt_error_to_generator_error)?;
283284
}
284285

linkml-service/src/generator/typeql_constraints.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! This module provides comprehensive constraint translation from `LinkML` to `TypeQL`,
44
//! supporting `TypeDB` 3.0 features including @card, @key, @unique, and regex patterns.
55
6+
use crate::utils::safe_cast::u64_to_usize_saturating;
67
use linkml_core::prelude::*;
78
use std::fmt::Write;
89
use std::collections::HashMap;
@@ -103,7 +104,7 @@ impl TypeQLConstraintTranslator {
103104
if slot.multivalued == Some(true) {
104105
// Check for explicit max cardinality
105106
if let Some(serde_json::Value::Number(max)) = &slot.maximum_value {
106-
max.as_u64().map(|n| n as usize)
107+
max.as_u64().map(u64_to_usize_saturating)
107108
} else {
108109
None // Unbounded
109110
}

linkml-service/src/generator/typeql_relation_analyzer.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
//! to generate optimal `TypeQL` relations, including multi-way relations,
55
//! nested relations, and role detection.
66
7+
use crate::utils::safe_cast::u64_to_usize_saturating;
78
use linkml_core::prelude::*;
89
use serde_json::Value;
910
use std::collections::{HashMap, HashSet};
@@ -211,7 +212,7 @@ impl RelationAnalyzer {
211212
let min = usize::from(slot.required.unwrap_or(false));
212213
let max = if slot.multivalued.unwrap_or(false) {
213214
if let Some(Value::Number(max_card)) = &slot.maximum_value {
214-
max_card.as_u64().map(|n| n as usize)
215+
max_card.as_u64().map(u64_to_usize_saturating)
215216
} else {
216217
None
217218
}

linkml-service/src/pattern/named_captures.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! This module provides advanced named capture functionality for pattern matching,
44
//! including type conversion, validation, and extraction utilities.
55
6+
use crate::utils::safe_cast::i64_to_f64_lossy;
67
use regex::Regex;
78
use serde::{Deserialize, Serialize};
89
use std::collections::HashMap;
@@ -376,7 +377,7 @@ impl CaptureValue {
376377
#[must_use] pub fn as_float(&self) -> Option<f64> {
377378
match self {
378379
CaptureValue::Float(f) => Some(*f),
379-
CaptureValue::Integer(i) => Some(*i as f64),
380+
CaptureValue::Integer(i) => Some(i64_to_f64_lossy(*i)),
380381
_ => None}
381382
}
382383

linkml-service/src/transform/schema_diff.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
//! This module provides functionality to compute differences between `LinkML` schemas,
44
//! including structural differences, semantic changes, and breaking change detection.
55
6+
use crate::utils::safe_cast::usize_to_f64;
67
use linkml_core::prelude::*;
78
use serde::{Deserialize, Serialize};
89
use std::collections::{HashMap, HashSet};
@@ -307,8 +308,8 @@ impl SchemaDiffer {
307308
// Compare attributes
308309
let old_attrs: HashSet<_> = old_class.attributes.keys().cloned().collect();
309310
let new_attrs: HashSet<_> = new_class.attributes.keys().cloned().collect();
310-
let attr_intersection = old_attrs.intersection(&new_attrs).count() as f64;
311-
let attr_union = old_attrs.union(&new_attrs).count() as f64;
311+
let attr_intersection = usize_to_f64(old_attrs.intersection(&new_attrs).count());
312+
let attr_union = usize_to_f64(old_attrs.union(&new_attrs).count());
312313

313314
if attr_union > 0.0 {
314315
score += attr_intersection / attr_union;
@@ -330,8 +331,8 @@ impl SchemaDiffer {
330331
// Compare mixins
331332
let old_mixins: HashSet<_> = old_class.mixins.iter().cloned().collect();
332333
let new_mixins: HashSet<_> = new_class.mixins.iter().cloned().collect();
333-
let mixin_intersection = old_mixins.intersection(&new_mixins).count() as f64;
334-
let mixin_union = old_mixins.union(&new_mixins).count() as f64;
334+
let mixin_intersection = usize_to_f64(old_mixins.intersection(&new_mixins).count());
335+
let mixin_union = usize_to_f64(old_mixins.union(&new_mixins).count());
335336

336337
if mixin_union > 0.0 {
337338
score += mixin_intersection / mixin_union;

linkml-service/src/utils/safe_cast.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,54 @@ pub fn f32_to_usize_saturating(value: f32) -> usize {
135135
}
136136
}
137137

138+
/// Safely cast u128 to u64 with saturation
139+
#[must_use]
140+
pub fn u128_to_u64_saturating(value: u128) -> u64 {
141+
if value > u64::MAX as u128 {
142+
u64::MAX
143+
} else {
144+
value as u64
145+
}
146+
}
147+
148+
/// Safely cast u64 to usize with saturation
149+
#[must_use]
150+
pub fn u64_to_usize_saturating(value: u64) -> usize {
151+
if value > usize::MAX as u64 {
152+
usize::MAX
153+
} else {
154+
value as usize
155+
}
156+
}
157+
158+
/// Safely cast f64 to i64 with saturation and rounding
159+
#[must_use]
160+
pub fn f64_to_i64_saturating(value: f64) -> i64 {
161+
if value > i64::MAX as f64 {
162+
i64::MAX
163+
} else if value < i64::MIN as f64 {
164+
i64::MIN
165+
} else if value.is_nan() {
166+
0
167+
} else {
168+
value.round() as i64
169+
}
170+
}
171+
172+
/// Safely cast f64 to usize with saturation and rounding
173+
#[must_use]
174+
pub fn f64_to_usize_saturating(value: f64) -> usize {
175+
if value < 0.0 {
176+
0
177+
} else if value > usize::MAX as f64 {
178+
usize::MAX
179+
} else if value.is_nan() {
180+
0
181+
} else {
182+
value.round() as usize
183+
}
184+
}
185+
138186
#[cfg(test)]
139187
mod tests {
140188
use super::*;

linkml-service/src/validator/engine.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
//! Main validation engine
22
33
use crate::performance::profiling::Profiler;
4+
use crate::utils::safe_cast::u128_to_u64_saturating;
45
use linkml_core::{
56
error::{LinkMLError, Result},
67
settings::SchemaSettings,
@@ -747,7 +748,7 @@ impl ValidationEngine {
747748
.map_err(|e| LinkMLError::service(format!("Failed to get system time: {e}")))?;
748749
let duration = end.duration_since(start)
749750
.map_err(|e| LinkMLError::service(format!("Time calculation error: {e}")))?;
750-
report.stats.duration_ms = duration.as_millis().min(u64::MAX as u128) as u64;
751+
report.stats.duration_ms = u128_to_u64_saturating(duration.as_millis());
751752
Ok(report)
752753
}
753754

linkml-service/src/validator/resource_limiter.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! - Request rate limiting
88
//! - Timeout enforcement
99
10-
use crate::utils::safe_cast::{usize_to_f64, usize_to_f32_saturating};
10+
use crate::utils::safe_cast::{usize_to_f64, usize_to_f32_saturating, u64_to_usize_saturating};
1111
use dashmap::DashMap;
1212
use parking_lot::{Mutex, RwLock};
1313
use linkml_core::{LinkMLError, Result};
@@ -560,7 +560,7 @@ impl ResourceMonitor for SystemResourceMonitor {
560560
// Note: sysinfo::System doesn't implement Clone, so we create a new instance
561561
let mut system = sysinfo::System::new();
562562
system.refresh_memory();
563-
system.used_memory() as usize
563+
u64_to_usize_saturating(system.used_memory())
564564
}
565565

566566
fn get_cpu_usage(&self) -> f32 {

0 commit comments

Comments
 (0)