Guest User

Untitled

a guest
Jul 20th, 2018
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.57 KB | None | 0 0
  1. use std::{fmt, str, mem};
  2. use std::sync::Mutex;
  3. use std::collections::HashSet;
  4.  
  5. #[derive(Copy, Clone)]
  6. pub struct InternedStr<'interner>(&'interner str);
  7.  
  8. impl PartialEq for InternedStr<'interner> {
  9. fn eq(&self, other: &InternedStr<'interner>) -> bool {
  10. let a = self.0 as *const str;
  11. let b = other.0 as *const str;
  12. a.eq(&b)
  13. }
  14. }
  15.  
  16. impl fmt::Display for InternedStr<'interner> {
  17. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  18. write!(f, "{}", self.0)
  19. }
  20. }
  21.  
  22. impl fmt::Debug for InternedStr<'interner> {
  23. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  24. write!(f, "\"{}\" ({:?})", self.0, self.0 as *const str)
  25. }
  26. }
  27.  
  28. pub struct StringInterner {
  29. interned_strings: Mutex<HashSet<String>>,
  30. }
  31.  
  32. impl StringInterner {
  33. pub fn new() -> StringInterner {
  34. StringInterner {
  35. interned_strings: Mutex::new(HashSet::new()),
  36. }
  37. }
  38.  
  39. pub fn intern_string(&'interner self, to_intern: &str) -> InternedStr<'interner> {
  40. // TODO(zac): @UNWRAP - Is there a way we want to gracefully handle the Mutex being
  41. // poisoned?
  42. let mut interned_strings = self.interned_strings.lock().unwrap();
  43.  
  44. if let Some(interned) = (*interned_strings).get(to_intern) {
  45. // @UNSAFE - NOTE(zac): This unsafe converts this string slice into having the lifetime of the
  46. // string interner.
  47. //
  48. // This *should* be safe, as the actual string should only be dropped when this object
  49. // is dropped.
  50. let slice = unsafe { mem::transmute(interned as &str) };
  51. return InternedStr(slice);
  52. }
  53.  
  54. let created = String::from(to_intern);
  55. // @UNSAFE - NOTE(zac): This unsafe converts this string slice into having the lifetime of the
  56. // string interner.
  57. //
  58. // This *should* be safe, if I understand correctly, as 'created' will not be dropped until
  59. // the string interner is dropped, and we are tying the lifetime of the interned string to
  60. // this object.
  61. let slice = unsafe { mem::transmute(&created as &str) };
  62.  
  63. (*interned_strings).insert(created);
  64. InternedStr(slice)
  65. }
  66. }
  67.  
  68. #[cfg(test)]
  69. mod tests {
  70. use super::*;
  71.  
  72. #[test]
  73. fn test_passing_interred_strings_across_threads() {
  74. use std::sync::Arc;
  75. use std::thread;
  76.  
  77. let interner = Arc::new(StringInterner::new());
  78.  
  79. let mut handlers = Vec::new();
  80. for _ in 0..3 {
  81. let interner = interner.clone();
  82.  
  83. let handler = thread::spawn(move || {
  84. // TODO(zac): We should be able to safely pass this data
  85. // across threads...
  86. interner.intern_string("Hello")
  87. });
  88.  
  89. handlers.push(handler);
  90. }
  91.  
  92. interner.intern_string("world");
  93.  
  94. for handler in handlers {
  95. handler.join().unwrap();
  96. }
  97. }
  98.  
  99. #[test]
  100. fn test_interned_string_equality_is_pointer_based() {
  101. let string = "interned";
  102. let other_string = "interned".to_string();
  103.  
  104. // The same byte array is equal.
  105. let a = InternedStr(string);
  106. let b = InternedStr(string);
  107. assert_eq!(a, b);
  108.  
  109. // Different string arrays are not equal, even if they
  110. // contain exactly the same characters.
  111. let a = InternedStr(string);
  112. let b = InternedStr(&other_string);
  113. assert_ne!(a, b);
  114. }
  115.  
  116. #[test]
  117. fn test_interned_string_display_displays_string() {
  118. let string = "interned";
  119. assert_eq!(format!("{}", InternedStr(string)), "interned");
  120. }
  121. }
Add Comment
Please, Sign In to add comment