quantrs2_device/neutral_atom/
tweezer_arrays.rs

1//! Optical tweezer array management for neutral atom quantum computing
2//!
3//! This module provides implementations for managing optical tweezer arrays,
4//! including atom loading, positioning, manipulation, and optimization.
5
6use crate::{DeviceError, DeviceResult};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::time::Duration;
10
11/// Optical tweezer configuration
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct TweezerArrayConfig {
14    /// Array dimensions (x, y, z)
15    pub array_dimensions: (usize, usize, usize),
16    /// Tweezer spacing (μm)
17    pub tweezer_spacing: (f64, f64, f64),
18    /// Laser wavelength (nm)
19    pub laser_wavelength: f64,
20    /// Beam waist (μm)
21    pub beam_waist: f64,
22    /// Maximum laser power (mW)
23    pub max_laser_power: f64,
24    /// Trap depth (μK)
25    pub trap_depth: f64,
26    /// Loading efficiency
27    pub loading_efficiency: f64,
28    /// Movement precision (nm)
29    pub movement_precision: f64,
30}
31
32/// Tweezer position in 3D space
33#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
34pub struct TweezerPosition {
35    /// X coordinate (μm)
36    pub x: f64,
37    /// Y coordinate (μm)
38    pub y: f64,
39    /// Z coordinate (μm)
40    pub z: f64,
41}
42
43/// Atom state in a tweezer
44#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
45pub enum AtomState {
46    /// No atom present
47    Empty,
48    /// Atom loaded successfully
49    Loaded,
50    /// Atom loading failed
51    LoadingFailed,
52    /// Atom lost during operation
53    Lost,
54    /// Atom in unknown state
55    Unknown,
56}
57
58/// Individual tweezer information
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct TweezerInfo {
61    /// Tweezer ID
62    pub tweezer_id: usize,
63    /// Current position
64    pub position: TweezerPosition,
65    /// Target position (for movement operations)
66    pub target_position: Option<TweezerPosition>,
67    /// Current laser power (mW)
68    pub laser_power: f64,
69    /// Atom state
70    pub atom_state: AtomState,
71    /// Loading attempt count
72    pub loading_attempts: usize,
73    /// Last update timestamp
74    pub last_update: std::time::SystemTime,
75}
76
77/// Tweezer array state
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub struct TweezerArrayState {
80    /// Configuration
81    pub config: TweezerArrayConfig,
82    /// Individual tweezers
83    pub tweezers: HashMap<usize, TweezerInfo>,
84    /// Array loading statistics
85    pub loading_stats: LoadingStatistics,
86    /// Movement operations in progress
87    pub active_movements: Vec<MovementOperation>,
88}
89
90/// Loading statistics
91#[derive(Debug, Clone, Serialize, Deserialize)]
92pub struct LoadingStatistics {
93    /// Total loading attempts
94    pub total_attempts: usize,
95    /// Successful loads
96    pub successful_loads: usize,
97    /// Failed loads
98    pub failed_loads: usize,
99    /// Current fill factor
100    pub fill_factor: f64,
101    /// Average loading time
102    pub average_loading_time: Duration,
103}
104
105/// Movement operation
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct MovementOperation {
108    /// Operation ID
109    pub operation_id: String,
110    /// Tweezer ID
111    pub tweezer_id: usize,
112    /// Start position
113    pub start_position: TweezerPosition,
114    /// End position
115    pub end_position: TweezerPosition,
116    /// Movement parameters
117    pub parameters: MovementParameters,
118    /// Start time
119    pub start_time: std::time::SystemTime,
120    /// Expected completion time
121    pub expected_completion: std::time::SystemTime,
122    /// Current status
123    pub status: MovementStatus,
124}
125
126/// Movement parameters
127#[derive(Debug, Clone, Serialize, Deserialize)]
128pub struct MovementParameters {
129    /// Movement speed (μm/s)
130    pub speed: f64,
131    /// Acceleration (μm/s²)
132    pub acceleration: f64,
133    /// Movement trajectory
134    pub trajectory: MovementTrajectory,
135    /// Power ramping during movement
136    pub power_ramping: PowerRampingConfig,
137}
138
139/// Movement trajectory types
140#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
141pub enum MovementTrajectory {
142    /// Direct linear path
143    Linear,
144    /// Smooth S-curve trajectory
145    SCurve,
146    /// Parabolic trajectory
147    Parabolic,
148    /// Custom waypoint-based trajectory
149    Waypoints(Vec<TweezerPosition>),
150}
151
152/// Power ramping configuration
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub struct PowerRampingConfig {
155    /// Enable power ramping
156    pub enabled: bool,
157    /// Initial power factor
158    pub initial_factor: f64,
159    /// Final power factor
160    pub final_factor: f64,
161    /// Ramping duration
162    pub ramping_duration: Duration,
163}
164
165/// Movement operation status
166#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
167pub enum MovementStatus {
168    /// Movement is queued
169    Queued,
170    /// Movement is in progress
171    InProgress,
172    /// Movement completed successfully
173    Completed,
174    /// Movement failed
175    Failed,
176    /// Movement was cancelled
177    Cancelled,
178}
179
180/// Tweezer array manager
181pub struct TweezerArrayManager {
182    state: TweezerArrayState,
183    movement_queue: Vec<MovementOperation>,
184    optimization_settings: OptimizationSettings,
185}
186
187/// Array optimization settings
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct OptimizationSettings {
190    /// Enable automatic reloading
191    pub auto_reload: bool,
192    /// Maximum reloading attempts
193    pub max_reload_attempts: usize,
194    /// Enable position optimization
195    pub position_optimization: bool,
196    /// Enable power optimization
197    pub power_optimization: bool,
198    /// Optimization interval
199    pub optimization_interval: Duration,
200}
201
202impl TweezerArrayManager {
203    /// Create a new tweezer array manager
204    pub fn new(config: TweezerArrayConfig) -> Self {
205        let total_tweezers =
206            config.array_dimensions.0 * config.array_dimensions.1 * config.array_dimensions.2;
207        let mut tweezers = HashMap::new();
208
209        // Initialize tweezers
210        for i in 0..total_tweezers {
211            let (x_idx, y_idx, z_idx) = Self::index_to_coordinates(i, &config.array_dimensions);
212            let position = TweezerPosition {
213                x: x_idx as f64 * config.tweezer_spacing.0,
214                y: y_idx as f64 * config.tweezer_spacing.1,
215                z: z_idx as f64 * config.tweezer_spacing.2,
216            };
217
218            let tweezer_info = TweezerInfo {
219                tweezer_id: i,
220                position,
221                target_position: None,
222                laser_power: 0.0,
223                atom_state: AtomState::Empty,
224                loading_attempts: 0,
225                last_update: std::time::SystemTime::now(),
226            };
227
228            tweezers.insert(i, tweezer_info);
229        }
230
231        let state = TweezerArrayState {
232            config,
233            tweezers,
234            loading_stats: LoadingStatistics::default(),
235            active_movements: Vec::new(),
236        };
237
238        Self {
239            state,
240            movement_queue: Vec::new(),
241            optimization_settings: OptimizationSettings::default(),
242        }
243    }
244
245    /// Convert linear index to 3D coordinates
246    const fn index_to_coordinates(
247        index: usize,
248        dimensions: &(usize, usize, usize),
249    ) -> (usize, usize, usize) {
250        let z_idx = index / (dimensions.0 * dimensions.1);
251        let y_idx = (index % (dimensions.0 * dimensions.1)) / dimensions.0;
252        let x_idx = index % dimensions.0;
253        (x_idx, y_idx, z_idx)
254    }
255
256    /// Convert 3D coordinates to linear index
257    const fn coordinates_to_index(
258        x: usize,
259        y: usize,
260        z: usize,
261        dimensions: &(usize, usize, usize),
262    ) -> usize {
263        z * dimensions.0 * dimensions.1 + y * dimensions.0 + x
264    }
265
266    /// Load atoms into specified tweezers
267    pub async fn load_atoms(&mut self, tweezer_ids: &[usize]) -> DeviceResult<LoadingResult> {
268        let mut results = HashMap::new();
269        let start_time = std::time::SystemTime::now();
270
271        for &tweezer_id in tweezer_ids {
272            let loading_result = self.load_single_atom(tweezer_id).await?;
273            results.insert(tweezer_id, loading_result);
274        }
275
276        // Update loading statistics
277        self.update_loading_statistics(&results, start_time);
278
279        Ok(LoadingResult {
280            attempted_tweezers: tweezer_ids.to_vec(),
281            successful_loads: results.values().filter(|&&success| success).count(),
282            failed_loads: results.values().filter(|&&success| !success).count(),
283            individual_results: results,
284            loading_time: start_time.elapsed().unwrap_or(Duration::ZERO),
285        })
286    }
287
288    /// Load a single atom into a tweezer
289    async fn load_single_atom(&mut self, tweezer_id: usize) -> DeviceResult<bool> {
290        // First, get the tweezer info for loading calculation
291        let (loading_attempts, base_success_rate) = {
292            let tweezer = self.state.tweezers.get(&tweezer_id).ok_or_else(|| {
293                DeviceError::InvalidInput(format!("Tweezer {tweezer_id} not found"))
294            })?;
295            (
296                tweezer.loading_attempts,
297                self.state.config.loading_efficiency,
298            )
299        };
300
301        // Calculate loading success
302        let loading_success =
303            self.simulate_atom_loading_from_params(loading_attempts, base_success_rate);
304
305        // Now update the tweezer
306        let tweezer =
307            self.state.tweezers.get_mut(&tweezer_id).ok_or_else(|| {
308                DeviceError::InvalidInput(format!("Tweezer {tweezer_id} not found"))
309            })?;
310
311        tweezer.loading_attempts += 1;
312        tweezer.last_update = std::time::SystemTime::now();
313        tweezer.atom_state = if loading_success {
314            AtomState::Loaded
315        } else {
316            AtomState::LoadingFailed
317        };
318
319        Ok(loading_success)
320    }
321
322    /// Simulate atom loading (mock implementation)
323    fn simulate_atom_loading(&self, tweezer: &TweezerInfo) -> bool {
324        self.simulate_atom_loading_from_params(
325            tweezer.loading_attempts,
326            self.state.config.loading_efficiency,
327        )
328    }
329
330    /// Simulate atom loading from parameters
331    fn simulate_atom_loading_from_params(
332        &self,
333        loading_attempts: usize,
334        base_success_rate: f64,
335    ) -> bool {
336        // Simple mock based on loading efficiency and number of attempts
337        let attempt_penalty = 0.05 * (loading_attempts as f64).max(1.0);
338        let effective_success_rate = (base_success_rate - attempt_penalty).max(0.1);
339
340        // Mock random decision
341        use std::collections::hash_map::DefaultHasher;
342        use std::hash::{Hash, Hasher};
343
344        let mut hasher = DefaultHasher::new();
345        loading_attempts.hash(&mut hasher);
346        let hash = hasher.finish();
347        let random_value = (hash % 1000) as f64 / 1000.0;
348
349        random_value < effective_success_rate
350    }
351
352    /// Move an atom from one position to another
353    pub async fn move_atom(
354        &mut self,
355        tweezer_id: usize,
356        target_position: TweezerPosition,
357        parameters: MovementParameters,
358    ) -> DeviceResult<String> {
359        let tweezer =
360            self.state.tweezers.get(&tweezer_id).ok_or_else(|| {
361                DeviceError::InvalidInput(format!("Tweezer {tweezer_id} not found"))
362            })?;
363
364        if tweezer.atom_state != AtomState::Loaded {
365            return Err(DeviceError::InvalidInput(
366                "Cannot move atom: no atom loaded in tweezer".to_string(),
367            ));
368        }
369
370        let movement_time =
371            self.calculate_movement_time(&tweezer.position, &target_position, &parameters);
372        let operation_id = format!("move_{}", uuid::Uuid::new_v4());
373
374        let movement_op = MovementOperation {
375            operation_id: operation_id.clone(),
376            tweezer_id,
377            start_position: tweezer.position,
378            end_position: target_position,
379            parameters,
380            start_time: std::time::SystemTime::now(),
381            expected_completion: std::time::SystemTime::now() + movement_time,
382            status: MovementStatus::Queued,
383        };
384
385        self.movement_queue.push(movement_op);
386        Ok(operation_id)
387    }
388
389    /// Calculate movement time based on distance and parameters
390    fn calculate_movement_time(
391        &self,
392        start: &TweezerPosition,
393        end: &TweezerPosition,
394        parameters: &MovementParameters,
395    ) -> Duration {
396        let distance = Self::calculate_distance(start, end);
397        let time_seconds = distance / parameters.speed;
398        Duration::from_secs_f64(time_seconds)
399    }
400
401    /// Calculate distance between two positions
402    fn calculate_distance(pos1: &TweezerPosition, pos2: &TweezerPosition) -> f64 {
403        let dx = pos2.x - pos1.x;
404        let dy = pos2.y - pos1.y;
405        let dz = pos2.z - pos1.z;
406        dz.mul_add(dz, dx.mul_add(dx, dy * dy)).sqrt()
407    }
408
409    /// Process movement operations
410    pub async fn process_movements(&mut self) -> DeviceResult<()> {
411        let mut operations_to_start = Vec::new();
412        let mut operations_to_complete = Vec::new();
413        let mut completed_indices = Vec::new();
414
415        // First pass: identify operations that need processing
416        for (i, movement) in self.movement_queue.iter_mut().enumerate() {
417            match movement.status {
418                MovementStatus::Queued => {
419                    movement.status = MovementStatus::InProgress;
420                    operations_to_start.push(movement.clone());
421                }
422                MovementStatus::InProgress => {
423                    if std::time::SystemTime::now() >= movement.expected_completion {
424                        movement.status = MovementStatus::Completed;
425                        operations_to_complete.push(movement.clone());
426                        completed_indices.push(i);
427                    }
428                }
429                _ => {}
430            }
431        }
432
433        // Second pass: execute the operations
434        for operation in operations_to_start {
435            self.start_movement_execution(&operation).await?;
436        }
437
438        for operation in operations_to_complete {
439            self.complete_movement(&operation)?;
440        }
441
442        // Remove completed operations
443        for &i in completed_indices.iter().rev() {
444            self.movement_queue.remove(i);
445        }
446
447        Ok(())
448    }
449
450    /// Start executing a movement operation
451    async fn start_movement_execution(&mut self, movement: &MovementOperation) -> DeviceResult<()> {
452        // In real implementation, this would start the actual hardware movement
453        // For now, just update the target position
454        if let Some(tweezer) = self.state.tweezers.get_mut(&movement.tweezer_id) {
455            tweezer.target_position = Some(movement.end_position);
456        }
457        Ok(())
458    }
459
460    /// Complete a movement operation
461    fn complete_movement(&mut self, movement: &MovementOperation) -> DeviceResult<()> {
462        if let Some(tweezer) = self.state.tweezers.get_mut(&movement.tweezer_id) {
463            tweezer.position = movement.end_position;
464            tweezer.target_position = None;
465            tweezer.last_update = std::time::SystemTime::now();
466        }
467        Ok(())
468    }
469
470    /// Update loading statistics
471    fn update_loading_statistics(
472        &mut self,
473        results: &HashMap<usize, bool>,
474        start_time: std::time::SystemTime,
475    ) {
476        let successful = results.values().filter(|&&success| success).count();
477        let failed = results.values().filter(|&&success| !success).count();
478        let loading_time = start_time.elapsed().unwrap_or(Duration::ZERO);
479
480        self.state.loading_stats.total_attempts += results.len();
481        self.state.loading_stats.successful_loads += successful;
482        self.state.loading_stats.failed_loads += failed;
483
484        // Update average loading time
485        let total_ops = self.state.loading_stats.total_attempts;
486        let current_avg = self.state.loading_stats.average_loading_time;
487        let new_avg = (current_avg * (total_ops - 1) as u32 + loading_time) / total_ops as u32;
488        self.state.loading_stats.average_loading_time = new_avg;
489
490        // Update fill factor
491        let loaded_count = self
492            .state
493            .tweezers
494            .values()
495            .filter(|t| t.atom_state == AtomState::Loaded)
496            .count();
497        self.state.loading_stats.fill_factor =
498            loaded_count as f64 / self.state.tweezers.len() as f64;
499    }
500
501    /// Get current array state
502    pub const fn get_array_state(&self) -> &TweezerArrayState {
503        &self.state
504    }
505
506    /// Get loading statistics
507    pub const fn get_loading_statistics(&self) -> &LoadingStatistics {
508        &self.state.loading_stats
509    }
510
511    /// Get atom positions
512    pub fn get_atom_positions(&self) -> Vec<(usize, TweezerPosition)> {
513        self.state
514            .tweezers
515            .iter()
516            .filter(|(_, tweezer)| tweezer.atom_state == AtomState::Loaded)
517            .map(|(&id, tweezer)| (id, tweezer.position))
518            .collect()
519    }
520
521    /// Optimize array configuration
522    pub async fn optimize_array(&mut self) -> DeviceResult<OptimizationResult> {
523        let mut optimizations_applied = Vec::new();
524
525        if self.optimization_settings.auto_reload {
526            let reload_count = self.auto_reload_failed_tweezers().await?;
527            if reload_count > 0 {
528                optimizations_applied.push(format!("Reloaded {reload_count} failed tweezers"));
529            }
530        }
531
532        if self.optimization_settings.position_optimization {
533            let position_adjustments = self.optimize_positions().await?;
534            if position_adjustments > 0 {
535                optimizations_applied.push(format!("Adjusted {position_adjustments} positions"));
536            }
537        }
538
539        if self.optimization_settings.power_optimization {
540            let power_adjustments = self.optimize_power_levels().await?;
541            if power_adjustments > 0 {
542                optimizations_applied.push(format!("Optimized {power_adjustments} power levels"));
543            }
544        }
545
546        Ok(OptimizationResult {
547            optimizations_applied,
548            fill_factor_improvement: 0.0, // Would calculate actual improvement
549            loading_efficiency_improvement: 0.0,
550        })
551    }
552
553    /// Auto-reload failed tweezers
554    async fn auto_reload_failed_tweezers(&mut self) -> DeviceResult<usize> {
555        let failed_tweezer_ids: Vec<usize> = self
556            .state
557            .tweezers
558            .iter()
559            .filter(|(_, tweezer)| {
560                tweezer.atom_state == AtomState::LoadingFailed
561                    && tweezer.loading_attempts < self.optimization_settings.max_reload_attempts
562            })
563            .map(|(&id, _)| id)
564            .collect();
565
566        if !failed_tweezer_ids.is_empty() {
567            self.load_atoms(&failed_tweezer_ids).await?;
568        }
569
570        Ok(failed_tweezer_ids.len())
571    }
572
573    /// Optimize atom positions
574    async fn optimize_positions(&mut self) -> DeviceResult<usize> {
575        // Mock implementation - would implement actual position optimization
576        Ok(0)
577    }
578
579    /// Optimize laser power levels
580    async fn optimize_power_levels(&mut self) -> DeviceResult<usize> {
581        // Mock implementation - would implement actual power optimization
582        Ok(0)
583    }
584}
585
586/// Loading operation result
587#[derive(Debug, Clone, Serialize, Deserialize)]
588pub struct LoadingResult {
589    /// Tweezers that were attempted
590    pub attempted_tweezers: Vec<usize>,
591    /// Number of successful loads
592    pub successful_loads: usize,
593    /// Number of failed loads
594    pub failed_loads: usize,
595    /// Individual results for each tweezer
596    pub individual_results: HashMap<usize, bool>,
597    /// Total loading time
598    pub loading_time: Duration,
599}
600
601/// Optimization result
602#[derive(Debug, Clone, Serialize, Deserialize)]
603pub struct OptimizationResult {
604    /// Optimizations that were applied
605    pub optimizations_applied: Vec<String>,
606    /// Fill factor improvement
607    pub fill_factor_improvement: f64,
608    /// Loading efficiency improvement
609    pub loading_efficiency_improvement: f64,
610}
611
612impl Default for TweezerArrayConfig {
613    fn default() -> Self {
614        Self {
615            array_dimensions: (10, 10, 1),
616            tweezer_spacing: (5.0, 5.0, 0.0),
617            laser_wavelength: 1064.0,
618            beam_waist: 1.0,
619            max_laser_power: 100.0,
620            trap_depth: 1000.0,
621            loading_efficiency: 0.8,
622            movement_precision: 10.0,
623        }
624    }
625}
626
627impl Default for LoadingStatistics {
628    fn default() -> Self {
629        Self {
630            total_attempts: 0,
631            successful_loads: 0,
632            failed_loads: 0,
633            fill_factor: 0.0,
634            average_loading_time: Duration::ZERO,
635        }
636    }
637}
638
639impl Default for OptimizationSettings {
640    fn default() -> Self {
641        Self {
642            auto_reload: true,
643            max_reload_attempts: 3,
644            position_optimization: false,
645            power_optimization: false,
646            optimization_interval: Duration::from_secs(60),
647        }
648    }
649}
650
651impl Default for MovementParameters {
652    fn default() -> Self {
653        Self {
654            speed: 10.0,       // μm/s
655            acceleration: 5.0, // μm/s²
656            trajectory: MovementTrajectory::Linear,
657            power_ramping: PowerRampingConfig::default(),
658        }
659    }
660}
661
662impl Default for PowerRampingConfig {
663    fn default() -> Self {
664        Self {
665            enabled: false,
666            initial_factor: 1.0,
667            final_factor: 1.0,
668            ramping_duration: Duration::from_millis(100),
669        }
670    }
671}
672
673/// Create a basic tweezer array configuration
674pub fn create_basic_array_config(rows: usize, cols: usize, spacing: f64) -> TweezerArrayConfig {
675    TweezerArrayConfig {
676        array_dimensions: (rows, cols, 1),
677        tweezer_spacing: (spacing, spacing, 0.0),
678        ..Default::default()
679    }
680}
681
682/// Create movement parameters for fast movement
683pub const fn create_fast_movement_params() -> MovementParameters {
684    MovementParameters {
685        speed: 50.0,
686        acceleration: 20.0,
687        trajectory: MovementTrajectory::SCurve,
688        power_ramping: PowerRampingConfig {
689            enabled: true,
690            initial_factor: 1.2,
691            final_factor: 1.0,
692            ramping_duration: Duration::from_millis(50),
693        },
694    }
695}
696
697#[cfg(test)]
698mod tests {
699    use super::*;
700
701    #[test]
702    fn test_tweezer_array_creation() {
703        let config = TweezerArrayConfig::default();
704        let manager = TweezerArrayManager::new(config);
705
706        assert_eq!(manager.state.tweezers.len(), 100); // 10x10x1 array
707        assert!(manager
708            .state
709            .tweezers
710            .values()
711            .all(|t| t.atom_state == AtomState::Empty));
712    }
713
714    #[test]
715    fn test_coordinate_conversion() {
716        let dimensions = (3, 3, 2);
717
718        // Test index to coordinates
719        let (x, y, z) = TweezerArrayManager::index_to_coordinates(10, &dimensions);
720        assert_eq!((x, y, z), (1, 0, 1));
721
722        // Test coordinates to index
723        let index = TweezerArrayManager::coordinates_to_index(1, 0, 1, &dimensions);
724        assert_eq!(index, 10);
725    }
726
727    #[test]
728    fn test_distance_calculation() {
729        let pos1 = TweezerPosition {
730            x: 0.0,
731            y: 0.0,
732            z: 0.0,
733        };
734        let pos2 = TweezerPosition {
735            x: 3.0,
736            y: 4.0,
737            z: 0.0,
738        };
739
740        let distance = TweezerArrayManager::calculate_distance(&pos1, &pos2);
741        assert_eq!(distance, 5.0);
742    }
743}
744
745// Mock UUID implementation
746mod uuid {
747    use std::fmt;
748
749    pub struct Uuid([u8; 16]);
750
751    impl Uuid {
752        pub fn new_v4() -> Self {
753            use std::collections::hash_map::DefaultHasher;
754            use std::hash::{Hash, Hasher};
755            use std::time::SystemTime;
756
757            let mut hasher = DefaultHasher::new();
758            SystemTime::now().hash(&mut hasher);
759            let hash = hasher.finish();
760
761            let mut bytes = [0u8; 16];
762            bytes[0..8].copy_from_slice(&hash.to_le_bytes());
763            bytes[8..16].copy_from_slice(&hash.to_be_bytes());
764
765            Self(bytes)
766        }
767    }
768
769    impl fmt::Display for Uuid {
770        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771            write!(f, "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
772                self.0[0], self.0[1], self.0[2], self.0[3],
773                self.0[4], self.0[5],
774                self.0[6], self.0[7],
775                self.0[8], self.0[9],
776                self.0[10], self.0[11], self.0[12], self.0[13], self.0[14], self.0[15])
777        }
778    }
779}