Skip to content

Commit

Permalink
add phantom type to unique
Browse files Browse the repository at this point in the history
  • Loading branch information
eliknebel committed Nov 11, 2024
1 parent a7aaff1 commit 8f8d213
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 39 deletions.
42 changes: 26 additions & 16 deletions src/sprocket/context.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ pub type HandlerFn =
fn(Dynamic) -> Nil

pub type IdentifiableHandler {
IdentifiableHandler(id: Unique, handler: HandlerFn)
IdentifiableHandler(id: Unique(HookId), handler: HandlerFn)
}

pub type Attribute {
Attribute(name: String, value: Dynamic)
Event(name: String, handler: IdentifiableHandler)
ClientHook(id: Unique, name: String)
ClientHook(id: Unique(HookId), name: String)
}

pub type AbstractFunctionalComponent =
Expand Down Expand Up @@ -75,23 +75,33 @@ pub type ClientDispatcher =
pub type ClientEventHandler =
fn(String, Option(Dynamic), ClientDispatcher) -> Nil

pub type HookId

pub type Hook {
Callback(id: Unique, callback: fn() -> Nil, prev: Option(CallbackResult))
Memo(id: Unique, value: Dynamic, prev: Option(MemoResult))
Callback(
id: Unique(HookId),
callback: fn() -> Nil,
prev: Option(CallbackResult),
)
Memo(id: Unique(HookId), value: Dynamic, prev: Option(MemoResult))
Effect(
id: Unique,
id: Unique(HookId),
effect: fn() -> EffectCleanup,
deps: HookDependencies,
prev: Option(EffectResult),
)
Handler(id: Unique, handler_fn: HandlerFn)
Reducer(id: Unique, reducer: Dynamic, cleanup: fn() -> Nil)
State(id: Unique, value: Dynamic)
Client(id: Unique, name: String, handle_event: Option(ClientEventHandler))
Handler(id: Unique(HookId), handler_fn: HandlerFn)
Reducer(id: Unique(HookId), reducer: Dynamic, cleanup: fn() -> Nil)
State(id: Unique(HookId), value: Dynamic)
Client(
id: Unique(HookId),
name: String,
handle_event: Option(ClientEventHandler),
)
}

// Returns true if the hook has the given id
pub fn has_id(hook: Hook, hook_id: Unique) -> Bool {
pub fn has_id(hook: Hook, hook_id: Unique(HookId)) -> Bool {
case hook {
Callback(id, _, _) if id == hook_id -> True
Memo(id, _, _) if id == hook_id -> True
Expand Down Expand Up @@ -148,8 +158,8 @@ pub type Context {
wip: ComponentWip,
handlers: List(IdentifiableHandler),
render_update: fn() -> Nil,
update_hook: fn(Unique, fn(Hook) -> Hook) -> Nil,
emit: fn(Unique, String, Option(String)) -> Result(Nil, Nil),
update_hook: fn(Unique(HookId), fn(Hook) -> Hook) -> Nil,
emit: fn(Unique(HookId), String, Option(String)) -> Result(Nil, Nil),
cuid_channel: Subject(cuid.Message),
providers: Dict(String, Dynamic),
)
Expand All @@ -160,7 +170,7 @@ pub fn new(
cuid_channel: Subject(cuid.Message),
emitter: Option(EventEmitter),
render_update: fn() -> Nil,
update_hook: fn(Unique, fn(Hook) -> Hook) -> Nil,
update_hook: fn(Unique(HookId), fn(Hook) -> Hook) -> Nil,
) -> Context {
Context(
view: view,
Expand Down Expand Up @@ -246,15 +256,15 @@ pub fn update_hook(ctx: Context, hook: Hook, index: Int) -> Context {
pub fn push_event_handler(
ctx: Context,
identifiable_cb: IdentifiableHandler,
) -> #(Context, Unique) {
) -> #(Context, Unique(HookId)) {
let IdentifiableHandler(id, cb) = identifiable_cb

#(Context(..ctx, handlers: [IdentifiableHandler(id, cb), ..ctx.handlers]), id)
}

pub fn get_event_handler(
ctx: Context,
id: Unique,
id: Unique(HookId),
) -> #(Context, Result(IdentifiableHandler, Nil)) {
let handler =
list.find(ctx.handlers, fn(h) {
Expand All @@ -267,7 +277,7 @@ pub fn get_event_handler(

pub fn emit_event(
ctx: Context,
id: Unique,
id: Unique(HookId),
name: String,
payload: Option(String),
) {
Expand Down
6 changes: 3 additions & 3 deletions src/sprocket/hooks.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import gleam/result
import sprocket/context.{
type Attribute, type ClientDispatcher, type ClientEventHandler, type Context,
type EffectCleanup, type Element, type HandlerFn, type HookDependencies,
type IdentifiableHandler, Callback, CallbackResult, Changed, Client,
ClientHook, Context, Effect, Handler, IdentifiableHandler, Unchanged,
type HookId, type IdentifiableHandler, Callback, CallbackResult, Changed,
Client, ClientHook, Context, Effect, Handler, IdentifiableHandler, Unchanged,
compare_deps,
}
import sprocket/internal/exceptions.{throw_on_unexpected_hook_result}
Expand Down Expand Up @@ -75,7 +75,7 @@ fn maybe_trigger_update(
}

/// Client hook attribute that can be used to reference a client hook by its id.
pub fn client_hook(id: Unique, name: String) -> Attribute {
pub fn client_hook(id: Unique(HookId), name: String) -> Attribute {
ClientHook(id, name)
}

Expand Down
23 changes: 8 additions & 15 deletions src/sprocket/internal/utils/unique.gleam
Original file line number Diff line number Diff line change
@@ -1,44 +1,37 @@
import gleam/erlang/process.{type Subject}
import gleam/result
import ids/cuid
import ids/uuid
import sprocket/internal/logger

pub opaque type Unique {
pub opaque type Unique(kind) {
Unique(id: String)
}

pub fn uuid() -> Unique {
let assert Ok(id) =
uuid.generate_v4()
|> result.map_error(fn(error) {
logger.error("unique.uuid: failed to generate UUID")
error
})
pub fn uuid() -> Unique(kind) {
let assert Ok(id) = uuid.generate_v4()

Unique(id: id)
}

pub fn cuid(channel: Subject(cuid.Message)) -> Unique {
pub fn cuid(channel: Subject(cuid.Message)) -> Unique(kind) {
let id = cuid.generate(channel)

Unique(id: id)
}

pub fn slug(channel: Subject(cuid.Message), label: String) -> Unique {
pub fn slug(channel: Subject(cuid.Message), label: String) -> Unique(kind) {
let id = label <> "-" <> cuid.slug(channel)

Unique(id: id)
}

pub fn from_string(str: String) -> Unique {
pub fn from_string(str: String) -> Unique(kind) {
Unique(id: str)
}

pub fn to_string(unique: Unique) -> String {
pub fn to_string(unique: Unique(kind)) -> String {
unique.id
}

pub fn equals(a: Unique, b: Unique) -> Bool {
pub fn equals(a: Unique(kind), b: Unique(kind)) -> Bool {
a.id == b.id
}
10 changes: 5 additions & 5 deletions src/sprocket/runtime.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import gleam/result
import ids/cuid
import sprocket/context.{
type ComponentHooks, type Context, type EffectCleanup, type EffectResult,
type Element, type EventEmitter, type Hook, type HookDependencies,
type Element, type EventEmitter, type Hook, type HookDependencies, type HookId,
type IdentifiableHandler, type Updater, Callback, Changed, Client, Context,
Effect, EffectResult, Handler, IdentifiableHandler, Memo, Reducer, Unchanged,
Updater, compare_deps,
Expand Down Expand Up @@ -66,7 +66,7 @@ pub opaque type Message {
payload: Option(Dynamic),
reply_emitter: fn(String, Option(String)) -> Result(Nil, Nil),
)
UpdateHookState(Unique, fn(Hook) -> Hook)
UpdateHookState(Unique(HookId), fn(Hook) -> Hook)
ReconcileImmediate(reply_with: Subject(ReconciledElement))
RenderUpdate
}
Expand Down Expand Up @@ -455,8 +455,8 @@ fn run_cleanup_for_disposed_hooks(

fn build_hooks_map(
node: ReconciledElement,
acc: Dict(Unique, Hook),
) -> Dict(Unique, Hook) {
acc: Dict(Unique(HookId), Hook),
) -> Dict(Unique(HookId), Hook) {
case node {
ReconciledComponent(_fc, _key, _props, hooks, el) -> {
// add hooks from this node
Expand Down Expand Up @@ -569,7 +569,7 @@ fn maybe_cleanup_and_rerun_effect(

fn find_and_update_hook(
reconciled: ReconciledElement,
hook_id: Unique,
hook_id: Unique(HookId),
update_fn: fn(Hook) -> Hook,
) -> ReconciledElement {
traverse_rendered_hooks(reconciled, fn(hook) {
Expand Down

0 comments on commit 8f8d213

Please sign in to comment.