@rustable/utils
Advanced tools
Comparing version 0.2.0 to 0.2.1
@@ -25,2 +25,7 @@ "use strict"; | ||
exports.Mut = mut.Mut; | ||
Object.defineProperty(exports, "Mut", { | ||
enumerable: true, | ||
get: function() { | ||
return mut.Mut; | ||
} | ||
}); |
@@ -0,32 +1,28 @@ | ||
export type Mut<T = object> = T & { | ||
[Mut.ptr]: T; | ||
}; | ||
export interface MutAccessors<T> { | ||
get: () => T; | ||
set: (value: T) => void; | ||
} | ||
/** | ||
* Represents a mutable reference with getter and setter functions. | ||
* @template T The type of the value being accessed. | ||
* @template S The type of the value being set, defaults to T. | ||
* Namespace for Mut-related functionality. | ||
*/ | ||
export declare class Mut<T, S = T> { | ||
private get; | ||
private set; | ||
export declare namespace Mut { | ||
/** | ||
* Creates a new Mut instance. | ||
* @param get Function to retrieve the current value. | ||
* @param set Function to set a new value. | ||
* Symbol used as a unique key for the pointer function. | ||
*/ | ||
constructor(get: () => T, set: (value: S) => void); | ||
const ptr: unique symbol; | ||
/** | ||
* Creates a new Mut instance. | ||
* @param get Function to retrieve the current value. | ||
* @param set Function to set a new value. | ||
* @returns A new Mut instance. | ||
* Replaces the entire value of a Mut object. | ||
* @param current The Mut object to modify. | ||
* @param newValue The new value to set. | ||
*/ | ||
static of<T, S = T>(get: () => T, set: (value: S) => void): Mut<T, S>; | ||
function replace<T>(current: Mut<T>, newValue: T): void; | ||
/** | ||
* Gets the current value. | ||
* @returns The current value of type T. | ||
* Creates a mutable reference that behaves like the original object | ||
* @param accessors Getter and setter functions | ||
* @returns A Mut instance that behaves like the original object | ||
*/ | ||
get value(): T; | ||
/** | ||
* Sets a new value. | ||
* @param newValue The new value to set, of type S. | ||
*/ | ||
set value(newValue: S); | ||
function of<T>(accessors: MutAccessors<T>): Mut<T>; | ||
} |
"use strict"; | ||
class Mut { | ||
constructor(get, set) { | ||
this.get = get; | ||
this.set = set; | ||
exports.Mut = void 0; | ||
(function(Mut2) { | ||
Mut2.ptr = Symbol("mut.ptr"); | ||
function replace(current, newValue) { | ||
current[Mut2.ptr] = newValue; | ||
} | ||
static of(get, set) { | ||
return new Mut(get, set); | ||
Mut2.replace = replace; | ||
function of(accessors) { | ||
return mut(accessors); | ||
} | ||
get value() { | ||
return this.get(); | ||
} | ||
set value(newValue) { | ||
this.set(newValue); | ||
} | ||
Mut2.of = of; | ||
})(exports.Mut || (exports.Mut = {})); | ||
function mut(accessors) { | ||
const {get: get, set: set} = accessors; | ||
const handler = { | ||
get(_, prop) { | ||
const current = get(); | ||
if (prop === exports.Mut.ptr) { | ||
return current; | ||
} | ||
const target = current; | ||
return typeof target[prop] === "function" ? target[prop].bind(target) : target[prop]; | ||
}, | ||
set(_, prop, value) { | ||
const current = get(); | ||
if (prop === exports.Mut.ptr) { | ||
set(value); | ||
return true; | ||
} | ||
current[prop] = value; | ||
return true; | ||
} | ||
}; | ||
return new Proxy({}, handler); | ||
} | ||
exports.Mut = Mut; |
{ | ||
"name": "@rustable/utils", | ||
"version": "0.2.0", | ||
"version": "0.2.1", | ||
"description": "Utility TypeScript utilities inspired by Rust, providing type-safe implementations of HashMap, TypeId, deep cloning, hashing, and equality comparison", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
177
README.md
@@ -49,2 +49,8 @@ # @rustable/utils | ||
### Immutable Reference (`ref.ts`) | ||
- Provides an immutable reference to values | ||
- Creates a deep clone of the original value | ||
- Supports independent modifications without affecting the original | ||
## Usage | ||
@@ -55,3 +61,3 @@ | ||
```typescript | ||
import { typeId, clone, hash, stringify, Mut } from '@rustable/utils'; | ||
import { typeId, clone, hash, stringify, Mut, Ref } from '@rustable/utils'; | ||
``` | ||
@@ -122,23 +128,157 @@ | ||
let value = 10; | ||
const mutRef = new Mut( | ||
() => value, | ||
(newValue) => { | ||
value = newValue; | ||
// Create a mutable object reference | ||
let obj = { name: 'Alice', age: 30 }; | ||
const mutRef = Mut.of({ | ||
get: () => obj, | ||
set: (newValue) => { | ||
obj = newValue; | ||
}, | ||
); | ||
}); | ||
console.log(mutRef.value); // Output: 10 | ||
mutRef.value = 20; | ||
console.log(mutRef.value); // Output: 20 | ||
// Access and modify properties directly | ||
console.log(mutRef.name); // Output: 'Alice' | ||
mutRef.age = 31; | ||
console.log(obj.age); // Output: 31 | ||
// Using Mut.of static method | ||
const anotherMutRef = Mut.of( | ||
() => value, | ||
(newValue) => { | ||
value = newValue; | ||
// Replace entire object using Mut.ptr | ||
mutRef[Mut.ptr] = { name: 'Bob', age: 25 }; | ||
console.log(obj); // Output: { name: 'Bob', age: 25 } | ||
// Get current value using Mut.ptr | ||
console.log(mutRef[Mut.ptr]); // Output: { name: 'Bob', age: 25 } | ||
// Replace using Mut.replace helper | ||
Mut.replace(mutRef, { name: 'Charlie', age: 20 }); | ||
console.log(obj); // Output: { name: 'Charlie', age: 20 } | ||
// Working with nested objects | ||
let nested = { | ||
info: { | ||
name: 'Alice', | ||
hobbies: ['reading'], | ||
}, | ||
); | ||
}; | ||
const nestedRef = Mut.of({ | ||
get: () => nested, | ||
set: (newValue) => { | ||
nested = newValue; | ||
}, | ||
}); | ||
// Modify nested properties | ||
nestedRef.info.hobbies.push('coding'); | ||
console.log(nested.info.hobbies); // Output: ['reading', 'coding'] | ||
// Replace nested object | ||
Mut.replace(nestedRef, { | ||
info: { | ||
name: 'Bob', | ||
hobbies: ['gaming'], | ||
}, | ||
}); | ||
console.log(nested); // Output: { info: { name: 'Bob', hobbies: ['gaming'] } } | ||
``` | ||
### Example: Using Immutable Reference | ||
```typescript | ||
import { Ref } from '@rustable/utils'; | ||
// Create a reference | ||
const obj = { name: 'Alice', age: 30 }; | ||
const ref = Ref.of(obj); | ||
// Modify the reference | ||
ref.name = 'Bob'; | ||
console.log(ref.name); // 'Bob' | ||
// Original remains unchanged | ||
console.log(obj.name); // 'Alice' | ||
// Access original through ptr | ||
console.log(ref[Ref.ptr].name); // 'Alice' | ||
``` | ||
## Ref | ||
The `Ref` type provides a way to create immutable references to values. Unlike `Mut`, which tracks mutations to the original value, `Ref` creates an independent copy that can be modified without affecting the original. | ||
### Usage | ||
```typescript | ||
import { Ref } from '@congeer/utils'; | ||
// Create a reference | ||
const obj = { name: 'Alice', age: 30 }; | ||
const ref = Ref.of(obj); | ||
// Modify the reference | ||
ref.name = 'Bob'; | ||
console.log(ref.name); // 'Bob' | ||
// Original remains unchanged | ||
console.log(obj.name); // 'Alice' | ||
// Access original through ptr | ||
console.log(ref[Ref.ptr].name); // 'Alice' | ||
``` | ||
### Features | ||
- **Deep Cloning**: Creates a deep clone of the original value, ensuring complete isolation | ||
- **Independent Modifications**: The reference can be freely modified without affecting the original | ||
- **Original Access**: The original value can be accessed through `Ref.ptr` symbol | ||
- **Method Support**: All methods work on the cloned value, preserving the original | ||
### Example with Complex Objects | ||
```typescript | ||
// Arrays | ||
const arr = [1, 2, 3]; | ||
const arrRef = Ref.of(arr); | ||
arrRef.push(4); | ||
console.log([...arrRef]); // [1, 2, 3, 4] | ||
console.log(arr); // [1, 2, 3] | ||
// Objects with Methods | ||
class User { | ||
constructor(public name: string) {} | ||
setName(name: string) { | ||
this.name = name; | ||
return this; | ||
} | ||
} | ||
const user = new User('Alice'); | ||
const userRef = Ref.of(user); | ||
userRef.setName('Bob'); | ||
console.log(userRef.name); // 'Bob' | ||
console.log(user.name); // 'Alice' | ||
``` | ||
### When to Use | ||
- When you need to experiment with modifications without affecting the original | ||
- When you want to maintain a separate copy of a value | ||
- When you need to compare modified state with original state | ||
- In scenarios where immutability of the original value is critical | ||
### Comparison with Mut | ||
While `Mut` tracks and propagates changes to the original value, `Ref` provides isolation: | ||
```typescript | ||
// Mut modifies original | ||
const mut = Mut.of({ value: 1 }); | ||
mut.value = 2; | ||
console.log(mut[Mut.ptr].value); // 2 | ||
// Ref keeps original unchanged | ||
const ref = Ref.of({ value: 1 }); | ||
ref.value = 2; | ||
console.log(ref[Ref.ptr].value); // 1 | ||
``` | ||
## Notes | ||
@@ -149,6 +289,7 @@ | ||
- Generic type support is available where applicable | ||
- The `Mut` class provides a way to create mutable references with custom getter and setter functions | ||
- The `Mut` type provides a proxy-based mutable reference that allows direct property access and modification | ||
- The `Ref` type provides an immutable reference to values, creating a deep clone of the original value | ||
## License | ||
MIT © illuxiza | ||
MIT illuxiza |
Sorry, the diff of this file is not supported yet
35880
25
865
292