1use std::borrow::Cow;
2use std::fmt;
3use std::sync::Arc;
4
5use super::{ElementType, VNextError, WeightComponentSpec, WeightId};
6
7pub unsafe trait StableHostMemory: Send + Sync + 'static {
18 fn stable_bytes(&self) -> &[u8];
19}
20
21#[derive(Clone)]
23pub struct RetainedHostMemoryRegion {
24 owner: Arc<dyn StableHostMemory>,
25 offset_bytes: usize,
26 length_bytes: usize,
27}
28
29impl RetainedHostMemoryRegion {
30 pub fn new<T>(
31 owner: Arc<T>,
32 offset_bytes: usize,
33 length_bytes: usize,
34 ) -> Result<Self, VNextError>
35 where
36 T: StableHostMemory,
37 {
38 let end = offset_bytes.checked_add(length_bytes).ok_or_else(|| {
39 VNextError::InvalidExecutionPlan {
40 reason: "retained host-memory range overflows the host address space".to_owned(),
41 }
42 })?;
43 if length_bytes == 0 || end > owner.stable_bytes().len() {
44 return Err(VNextError::InvalidExecutionPlan {
45 reason: "retained host-memory range is empty or exceeds its owner".to_owned(),
46 });
47 }
48 Ok(Self {
49 owner,
50 offset_bytes,
51 length_bytes,
52 })
53 }
54
55 pub fn bytes(&self) -> &[u8] {
56 &self.owner.stable_bytes()[self.offset_bytes..self.offset_bytes + self.length_bytes]
57 }
58
59 pub fn owner_bytes(&self) -> &[u8] {
63 self.owner.stable_bytes()
64 }
65
66 pub const fn offset_bytes(&self) -> usize {
67 self.offset_bytes
68 }
69
70 pub const fn length_bytes(&self) -> usize {
71 self.length_bytes
72 }
73}
74
75impl fmt::Debug for RetainedHostMemoryRegion {
76 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
77 formatter
78 .debug_struct("RetainedHostMemoryRegion")
79 .field("offset_bytes", &self.offset_bytes)
80 .field("length_bytes", &self.length_bytes)
81 .finish_non_exhaustive()
82 }
83}
84
85pub struct WeightComponentSegment<'source> {
92 bytes: Cow<'source, [u8]>,
93 retained_host_memory: Option<RetainedHostMemoryRegion>,
94}
95
96impl<'source> WeightComponentSegment<'source> {
97 pub fn new(bytes: impl Into<Cow<'source, [u8]>>) -> Self {
98 Self {
99 bytes: bytes.into(),
100 retained_host_memory: None,
101 }
102 }
103
104 pub fn with_retained_host_memory(
108 mut self,
109 retained_host_memory: RetainedHostMemoryRegion,
110 ) -> Result<Self, VNextError> {
111 let retained_bytes = retained_host_memory.bytes();
112 if retained_bytes.len() != self.bytes.len()
113 || !std::ptr::eq(retained_bytes.as_ptr(), self.bytes.as_ptr())
114 {
115 return Err(VNextError::InvalidExecutionPlan {
116 reason: "weight component segment retained host-memory region differs from its validated bytes"
117 .to_owned(),
118 });
119 }
120 self.retained_host_memory = Some(retained_host_memory);
121 Ok(self)
122 }
123
124 pub fn bytes(&self) -> &[u8] {
125 &self.bytes
126 }
127
128 pub fn retained_host_memory(&self) -> Option<&RetainedHostMemoryRegion> {
129 self.retained_host_memory.as_ref()
130 }
131}
132
133pub struct WeightComponentSegments<'source> {
142 component_id: WeightId,
143 external_names: Vec<String>,
144 source_files: Vec<String>,
145 dimensions: Vec<u64>,
146 element_type: ElementType,
147 segments: Vec<WeightComponentSegment<'source>>,
148}
149
150impl<'source> WeightComponentSegments<'source> {
151 pub fn from_ordered_segments(
152 component: &WeightComponentSpec,
153 external_names: Vec<String>,
154 source_files: Vec<String>,
155 dimensions: Vec<u64>,
156 element_type: ElementType,
157 segments: Vec<WeightComponentSegment<'source>>,
158 ) -> Result<Self, VNextError> {
159 let total_bytes = segments.iter().try_fold(0_u64, |total, segment| {
160 u64::try_from(segment.bytes().len())
161 .ok()
162 .and_then(|length| total.checked_add(length))
163 });
164 let sources_match = valid_ordered_sources(component, &external_names, &source_files);
165 let expected_bytes = component.physical_bytes()?;
166 if segments.is_empty()
167 || segments.iter().any(|segment| segment.bytes().is_empty())
168 || !sources_match
169 || dimensions != component.dimensions
170 || element_type != component.physical_element_type()
171 || total_bytes != Some(expected_bytes)
172 {
173 return Err(VNextError::InvalidExecutionPlan {
174 reason: format!(
175 "weight component `{}` segments differ from its schema identity, source, shape, type, or byte length",
176 component.id
177 ),
178 });
179 }
180 Ok(Self {
181 component_id: component.id.clone(),
182 external_names,
183 source_files,
184 dimensions,
185 element_type,
186 segments,
187 })
188 }
189
190 pub fn from_payload(payload: WeightComponentPayload<'source>) -> Self {
194 let WeightComponentPayload {
195 component_id,
196 external_names,
197 source_files,
198 dimensions,
199 element_type,
200 bytes,
201 retained_host_memory,
202 } = payload;
203 Self {
204 component_id,
205 external_names,
206 source_files,
207 dimensions,
208 element_type,
209 segments: vec![WeightComponentSegment {
210 bytes,
211 retained_host_memory,
212 }],
213 }
214 }
215
216 pub fn component_id(&self) -> &WeightId {
217 &self.component_id
218 }
219
220 pub fn external_names(&self) -> &[String] {
221 &self.external_names
222 }
223
224 pub fn source_files(&self) -> &[String] {
225 &self.source_files
226 }
227
228 pub fn dimensions(&self) -> &[u64] {
229 &self.dimensions
230 }
231
232 pub const fn element_type(&self) -> ElementType {
233 self.element_type
234 }
235
236 pub fn segments(&self) -> &[WeightComponentSegment<'source>] {
237 &self.segments
238 }
239
240 pub fn total_bytes(&self) -> u64 {
241 self.segments
242 .iter()
243 .map(|segment| segment.bytes().len() as u64)
244 .sum()
245 }
246}
247
248pub struct WeightComponentPayload<'source> {
253 component_id: WeightId,
254 external_names: Vec<String>,
255 source_files: Vec<String>,
256 dimensions: Vec<u64>,
257 element_type: ElementType,
258 bytes: Cow<'source, [u8]>,
259 retained_host_memory: Option<RetainedHostMemoryRegion>,
260}
261
262impl<'source> WeightComponentPayload<'source> {
263 pub fn new(
264 component: &WeightComponentSpec,
265 external_name: impl Into<String>,
266 source_file: impl Into<String>,
267 dimensions: Vec<u64>,
268 element_type: ElementType,
269 bytes: impl Into<Cow<'source, [u8]>>,
270 ) -> Result<Self, VNextError> {
271 Self::from_ordered_sources(
272 component,
273 vec![external_name.into()],
274 vec![source_file.into()],
275 dimensions,
276 element_type,
277 bytes,
278 )
279 }
280
281 pub fn from_ordered_sources(
285 component: &WeightComponentSpec,
286 external_names: Vec<String>,
287 source_files: Vec<String>,
288 dimensions: Vec<u64>,
289 element_type: ElementType,
290 bytes: impl Into<Cow<'source, [u8]>>,
291 ) -> Result<Self, VNextError> {
292 let bytes = bytes.into();
293 let sources_match = valid_ordered_sources(component, &external_names, &source_files);
294 let expected_bytes = component.physical_bytes()?;
295 if !sources_match
296 || dimensions != component.dimensions
297 || element_type != component.physical_element_type()
298 || u64::try_from(bytes.len()).ok() != Some(expected_bytes)
299 {
300 return Err(VNextError::InvalidExecutionPlan {
301 reason: format!(
302 "weight component `{}` payload differs from its schema identity, source, shape, type, or byte length",
303 component.id
304 ),
305 });
306 }
307 Ok(Self {
308 component_id: component.id.clone(),
309 external_names,
310 source_files,
311 dimensions,
312 element_type,
313 bytes,
314 retained_host_memory: None,
315 })
316 }
317
318 pub fn with_retained_host_memory(
322 mut self,
323 retained_host_memory: RetainedHostMemoryRegion,
324 ) -> Result<Self, VNextError> {
325 let retained_bytes = retained_host_memory.bytes();
326 if retained_bytes.len() != self.bytes.len()
327 || !std::ptr::eq(retained_bytes.as_ptr(), self.bytes.as_ptr())
328 {
329 return Err(VNextError::InvalidExecutionPlan {
330 reason: format!(
331 "weight component `{}` retained host-memory region differs from its validated payload",
332 self.component_id
333 ),
334 });
335 }
336 self.retained_host_memory = Some(retained_host_memory);
337 Ok(self)
338 }
339
340 pub fn component_id(&self) -> &WeightId {
341 &self.component_id
342 }
343
344 pub fn external_name(&self) -> &str {
345 &self.external_names[0]
346 }
347
348 pub fn source_file(&self) -> &str {
349 &self.source_files[0]
350 }
351
352 pub fn external_names(&self) -> &[String] {
353 &self.external_names
354 }
355
356 pub fn source_files(&self) -> &[String] {
357 &self.source_files
358 }
359
360 pub fn dimensions(&self) -> &[u64] {
361 &self.dimensions
362 }
363
364 pub const fn element_type(&self) -> ElementType {
365 self.element_type
366 }
367
368 pub fn bytes(&self) -> &[u8] {
369 &self.bytes
370 }
371
372 pub fn retained_host_memory(&self) -> Option<&RetainedHostMemoryRegion> {
373 self.retained_host_memory.as_ref()
374 }
375}
376
377pub trait WeightComponentSource: Send + Sync {
383 fn component<'source>(
384 &'source self,
385 component: &WeightComponentSpec,
386 ) -> Result<WeightComponentPayload<'source>, VNextError>;
387
388 fn component_segments<'source>(
395 &'source self,
396 component: &WeightComponentSpec,
397 ) -> Result<WeightComponentSegments<'source>, VNextError> {
398 self.component(component)
399 .map(WeightComponentSegments::from_payload)
400 }
401}
402
403fn valid_ordered_sources(
404 component: &WeightComponentSpec,
405 external_names: &[String],
406 source_files: &[String],
407) -> bool {
408 let valid_source_file = |source_file: &str| {
409 !source_file.is_empty()
410 && !source_file.starts_with('/')
411 && !source_file.contains('\\')
412 && source_file
413 .split('/')
414 .all(|component| !matches!(component, "" | "." | ".."))
415 };
416 !external_names.is_empty()
417 && external_names == component.external_names
418 && external_names.len() == source_files.len()
419 && source_files.iter().all(|file| valid_source_file(file))
420}
421
422#[cfg(test)]
423mod tests {
424 use super::*;
425 use crate::vnext::{BlockQuantizationSpec, WeightComponentRole, WeightEncoding};
426
427 struct StableBytes(Vec<u8>);
428
429 unsafe impl StableHostMemory for StableBytes {
432 fn stable_bytes(&self) -> &[u8] {
433 &self.0
434 }
435 }
436
437 struct ContiguousSource(Vec<u8>);
438
439 impl WeightComponentSource for ContiguousSource {
440 fn component<'source>(
441 &'source self,
442 component: &WeightComponentSpec,
443 ) -> Result<WeightComponentPayload<'source>, VNextError> {
444 WeightComponentPayload::from_ordered_sources(
445 component,
446 component.external_names.clone(),
447 vec![
448 "model-1.safetensors".to_owned(),
449 "model-2.safetensors".to_owned(),
450 ],
451 component.dimensions.clone(),
452 ElementType::F16,
453 self.0.as_slice(),
454 )
455 }
456 }
457
458 fn packed_component() -> WeightComponentSpec {
459 WeightComponentSpec {
460 id: WeightId::new("component.test.gate_up").unwrap(),
461 role: WeightComponentRole::Values,
462 external_names: vec!["gate.weight".to_owned(), "up.weight".to_owned()],
463 dimensions: vec![2, 2, 2],
464 encoding: WeightEncoding::Dense {
465 element_type: ElementType::F16,
466 },
467 required: true,
468 }
469 }
470
471 #[test]
472 fn packed_payload_preserves_ordered_source_identity() {
473 let component = packed_component();
474 let payload = WeightComponentPayload::from_ordered_sources(
475 &component,
476 component.external_names.clone(),
477 vec![
478 "model-1.safetensors".to_owned(),
479 "model-2.safetensors".to_owned(),
480 ],
481 component.dimensions.clone(),
482 ElementType::F16,
483 vec![0_u8; 16],
484 )
485 .unwrap();
486 assert_eq!(payload.external_names(), component.external_names);
487 assert_eq!(payload.source_files().len(), 2);
488
489 let error = WeightComponentPayload::from_ordered_sources(
490 &component,
491 component.external_names.iter().rev().cloned().collect(),
492 vec![
493 "model-2.safetensors".to_owned(),
494 "model-1.safetensors".to_owned(),
495 ],
496 component.dimensions.clone(),
497 ElementType::F16,
498 vec![0_u8; 16],
499 )
500 .err()
501 .expect("source order is part of the packed component identity");
502 assert!(error.to_string().contains("differs from its schema"));
503 }
504
505 #[test]
506 fn block_quantized_payload_validates_block_abi_byte_size() {
507 let component = WeightComponentSpec {
508 id: WeightId::new("component.test.q4-k").unwrap(),
509 role: WeightComponentRole::PackedValues,
510 external_names: vec!["weight.q4_k".to_owned()],
511 dimensions: vec![2],
512 encoding: WeightEncoding::BlockQuantized(BlockQuantizationSpec {
513 format_id: "quantization.gguf.q4-k".to_owned().try_into().unwrap(),
514 logical_values_per_block: 256,
515 bytes_per_block: 144,
516 }),
517 required: true,
518 };
519 let payload = WeightComponentPayload::new(
520 &component,
521 "weight.q4_k",
522 "model.gguf",
523 vec![2],
524 ElementType::U8,
525 vec![0_u8; 288],
526 )
527 .unwrap();
528 assert_eq!(payload.bytes().len(), 288);
529
530 let error = WeightComponentPayload::new(
531 &component,
532 "weight.q4_k",
533 "model.gguf",
534 vec![2],
535 ElementType::U8,
536 vec![0_u8; 2],
537 )
538 .err()
539 .expect("block-grid element count must not be mistaken for byte length");
540 assert!(error.to_string().contains("differs from its schema"));
541 }
542
543 #[test]
544 fn retained_region_must_be_the_validated_payload_and_keeps_its_owner_alive() {
545 let component = packed_component();
546 let owner = Arc::new(StableBytes(vec![7_u8; 32]));
547 let retained = RetainedHostMemoryRegion::new(Arc::clone(&owner), 8, 16).unwrap();
548 let payload = WeightComponentPayload::from_ordered_sources(
549 &component,
550 component.external_names.clone(),
551 vec![
552 "model-1.safetensors".to_owned(),
553 "model-2.safetensors".to_owned(),
554 ],
555 component.dimensions.clone(),
556 ElementType::F16,
557 retained.bytes(),
558 )
559 .unwrap()
560 .with_retained_host_memory(retained.clone())
561 .unwrap();
562 let retained = payload.retained_host_memory().unwrap().clone();
563 drop(payload);
564 drop(owner);
565 assert_eq!(retained.bytes(), &[7_u8; 16]);
566
567 let other = Arc::new(StableBytes(vec![7_u8; 16]));
568 let wrong = RetainedHostMemoryRegion::new(other, 0, 16).unwrap();
569 let result = WeightComponentPayload::from_ordered_sources(
570 &component,
571 component.external_names.clone(),
572 vec![
573 "model-1.safetensors".to_owned(),
574 "model-2.safetensors".to_owned(),
575 ],
576 component.dimensions.clone(),
577 ElementType::F16,
578 vec![7_u8; 16],
579 )
580 .unwrap()
581 .with_retained_host_memory(wrong);
582 let error = match result {
583 Ok(_) => panic!("a different allocation must not satisfy retained payload identity"),
584 Err(error) => error,
585 };
586 assert!(error
587 .to_string()
588 .contains("retained host-memory region differs"));
589 }
590
591 #[test]
592 fn ordered_segments_preserve_source_order_and_retain_each_exact_range() {
593 let component = packed_component();
594 let owner_a = Arc::new(StableBytes(vec![1_u8; 24]));
595 let owner_b = Arc::new(StableBytes(vec![2_u8; 24]));
596 let retained_a = RetainedHostMemoryRegion::new(Arc::clone(&owner_a), 4, 8).unwrap();
597 let retained_b = RetainedHostMemoryRegion::new(Arc::clone(&owner_b), 12, 8).unwrap();
598 let segments = WeightComponentSegments::from_ordered_segments(
599 &component,
600 component.external_names.clone(),
601 vec![
602 "model-1.safetensors".to_owned(),
603 "model-2.safetensors".to_owned(),
604 ],
605 component.dimensions.clone(),
606 ElementType::F16,
607 vec![
608 WeightComponentSegment::new(retained_a.bytes())
609 .with_retained_host_memory(retained_a.clone())
610 .unwrap(),
611 WeightComponentSegment::new(retained_b.bytes())
612 .with_retained_host_memory(retained_b.clone())
613 .unwrap(),
614 ],
615 )
616 .unwrap();
617
618 assert_eq!(segments.external_names(), component.external_names);
619 assert_eq!(segments.source_files().len(), 2);
620 assert_eq!(segments.total_bytes(), 16);
621 assert_eq!(segments.segments().len(), 2);
622 assert_eq!(segments.segments()[0].bytes(), &[1_u8; 8]);
623 assert_eq!(segments.segments()[1].bytes(), &[2_u8; 8]);
624 let retained_segments = segments
625 .segments()
626 .iter()
627 .map(|segment| segment.retained_host_memory().unwrap().clone())
628 .collect::<Vec<_>>();
629 drop(segments);
630 drop(retained_a);
631 drop(retained_b);
632 drop(owner_a);
633 drop(owner_b);
634 assert_eq!(retained_segments[0].bytes(), &[1_u8; 8]);
635 assert_eq!(retained_segments[1].bytes(), &[2_u8; 8]);
636 }
637
638 #[test]
639 fn component_segments_default_wraps_the_contiguous_payload_once() {
640 let component = packed_component();
641 let source = ContiguousSource(vec![3_u8; 16]);
642 let segments = source.component_segments(&component).unwrap();
643
644 assert_eq!(segments.component_id(), &component.id);
645 assert_eq!(segments.dimensions(), component.dimensions);
646 assert_eq!(segments.element_type(), ElementType::F16);
647 assert_eq!(segments.segments().len(), 1);
648 assert_eq!(segments.segments()[0].bytes(), &[3_u8; 16]);
649 }
650
651 #[test]
652 fn ordered_segments_reject_wrong_total_length_or_retained_range() {
653 let component = packed_component();
654 let error = WeightComponentSegments::from_ordered_segments(
655 &component,
656 component.external_names.clone(),
657 vec![
658 "model-1.safetensors".to_owned(),
659 "model-2.safetensors".to_owned(),
660 ],
661 component.dimensions.clone(),
662 ElementType::F16,
663 vec![WeightComponentSegment::new(vec![0_u8; 15])],
664 )
665 .err()
666 .expect("the segment total must match the physical component size");
667 assert!(error
668 .to_string()
669 .contains("segments differ from its schema"));
670
671 let bytes = vec![5_u8; 8];
672 let owner = Arc::new(StableBytes(vec![5_u8; 8]));
673 let retained = RetainedHostMemoryRegion::new(owner, 0, 8).unwrap();
674 let error = WeightComponentSegment::new(bytes)
675 .with_retained_host_memory(retained)
676 .err()
677 .expect("a different allocation must not satisfy segment retention");
678 assert!(error
679 .to_string()
680 .contains("retained host-memory region differs"));
681 }
682}