Skip to content

Commit 72e55b7

Browse files
SuttonKyleKyle Sutton
andauthored
allow Stream.split to use refinement for better type inference (#3917)
Co-authored-by: Kyle Sutton <[email protected]>
1 parent 1eb63d4 commit 72e55b7

File tree

4 files changed

+64
-40
lines changed

4 files changed

+64
-40
lines changed

.changeset/warm-meals-pretend.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"effect": patch
3+
---
4+
5+
Allow Stream.split to use refinement for better type inference

packages/effect/dtslint/Stream.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ Stream.dropUntil(numbersOrStrings, Predicate.isNumber)
177177
pipe(numbersOrStrings, Stream.dropUntil(Predicate.isNumber))
178178

179179
// -------------------------------------------------------------------------------------
180-
// splitWhere
180+
// split
181181
// -------------------------------------------------------------------------------------
182182

183183
// $ExpectType Stream<Chunk<number>, never, never>
@@ -186,10 +186,10 @@ Stream.split(numbers, predicateNumbersOrStrings)
186186
// $ExpectType Stream<Chunk<number>, never, never>
187187
pipe(numbers, Stream.split(predicateNumbersOrStrings))
188188

189-
// $ExpectType Stream<Chunk<string | number>, never, never>
189+
// $ExpectType Stream<Chunk<string>, never, never>
190190
Stream.split(numbersOrStrings, Predicate.isNumber)
191191

192-
// $ExpectType Stream<Chunk<string | number>, never, never>
192+
// $ExpectType Stream<Chunk<string>, never, never>
193193
pipe(numbersOrStrings, Stream.split(Predicate.isNumber))
194194

195195
// -------------------------------------------------------------------------------------

packages/effect/src/Stream.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4548,7 +4548,7 @@ export const someOrFail: {
45484548
} = internal.someOrFail
45494549

45504550
/**
4551-
* Splits elements based on a predicate.
4551+
* Splits elements based on a predicate or refinement.
45524552
*
45534553
* ```ts
45544554
* import * as Stream from "./Stream"
@@ -4566,7 +4566,11 @@ export const someOrFail: {
45664566
* @category utils
45674567
*/
45684568
export const split: {
4569+
<A, B extends A>(
4570+
refinement: Refinement<NoInfer<A>, B>
4571+
): <E, R>(self: Stream<A, E, R>) => Stream<Chunk.Chunk<Exclude<A, B>>, E, R>
45694572
<A>(predicate: Predicate<NoInfer<A>>): <E, R>(self: Stream<A, E, R>) => Stream<Chunk.Chunk<A>, E, R>
4573+
<A, E, R, B extends A>(self: Stream<A, E, R>, refinement: Refinement<A, B>): Stream<Chunk.Chunk<Exclude<A, B>>, E, R>
45704574
<A, E, R>(self: Stream<A, E, R>, predicate: Predicate<A>): Stream<Chunk.Chunk<A>, E, R>
45714575
} = internal.split
45724576

packages/effect/src/internal/stream.ts

Lines changed: 51 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6189,44 +6189,59 @@ export const slidingSize = dual<
61896189
)
61906190

61916191
/** @internal */
6192-
export const split = dual<
6193-
<A>(predicate: Predicate<NoInfer<A>>) => <E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<Chunk.Chunk<A>, E, R>,
6194-
<A, E, R>(self: Stream.Stream<A, E, R>, predicate: Predicate<A>) => Stream.Stream<Chunk.Chunk<A>, E, R>
6195-
>(2, <A, E, R>(self: Stream.Stream<A, E, R>, predicate: Predicate<A>): Stream.Stream<Chunk.Chunk<A>, E, R> => {
6196-
const split = (
6197-
leftovers: Chunk.Chunk<A>,
6198-
input: Chunk.Chunk<A>
6199-
): Channel.Channel<Chunk.Chunk<Chunk.Chunk<A>>, Chunk.Chunk<A>, E, E, unknown, unknown, R> => {
6200-
const [chunk, remaining] = pipe(leftovers, Chunk.appendAll(input), Chunk.splitWhere(predicate))
6201-
if (Chunk.isEmpty(chunk) || Chunk.isEmpty(remaining)) {
6202-
return loop(pipe(chunk, Chunk.appendAll(pipe(remaining, Chunk.drop(1)))))
6192+
export const split: {
6193+
<A, B extends A>(
6194+
refinement: Refinement<NoInfer<A>, B>
6195+
): <E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<Chunk.Chunk<Exclude<A, B>>, E, R>
6196+
<A>(
6197+
predicate: Predicate<NoInfer<A>>
6198+
): <E, R>(self: Stream.Stream<A, E, R>) => Stream.Stream<Chunk.Chunk<A>, E, R>
6199+
<A, E, R, B extends A>(
6200+
self: Stream.Stream<A, E, R>,
6201+
refinement: Refinement<A, B>
6202+
): Stream.Stream<Chunk.Chunk<Exclude<A, B>>, E, R>
6203+
<A, E, R>(self: Stream.Stream<A, E, R>, predicate: Predicate<A>): Stream.Stream<Chunk.Chunk<A>, E, R>
6204+
} = dual(
6205+
2,
6206+
<A, E, R>(
6207+
self: Stream.Stream<A, E, R>,
6208+
predicate: Predicate<A>
6209+
): Stream.Stream<Chunk.Chunk<A>, E, R> => {
6210+
const split = (
6211+
leftovers: Chunk.Chunk<A>,
6212+
input: Chunk.Chunk<A>
6213+
): Channel.Channel<Chunk.Chunk<Chunk.Chunk<A>>, Chunk.Chunk<A>, E, E, unknown, unknown, R> => {
6214+
const [chunk, remaining] = pipe(leftovers, Chunk.appendAll(input), Chunk.splitWhere(predicate))
6215+
if (Chunk.isEmpty(chunk) || Chunk.isEmpty(remaining)) {
6216+
return loop(pipe(chunk, Chunk.appendAll(pipe(remaining, Chunk.drop(1)))))
6217+
}
6218+
return pipe(
6219+
core.write(Chunk.of(chunk)),
6220+
core.flatMap(() => split(Chunk.empty(), pipe(remaining, Chunk.drop(1))))
6221+
)
62036222
}
6204-
return pipe(
6205-
core.write(Chunk.of(chunk)),
6206-
core.flatMap(() => split(Chunk.empty(), pipe(remaining, Chunk.drop(1))))
6207-
)
6208-
}
6209-
const loop = (
6210-
leftovers: Chunk.Chunk<A>
6211-
): Channel.Channel<Chunk.Chunk<Chunk.Chunk<A>>, Chunk.Chunk<A>, E, E, unknown, unknown, R> =>
6212-
core.readWith({
6213-
onInput: (input: Chunk.Chunk<A>) => split(leftovers, input),
6214-
onFailure: core.fail,
6215-
onDone: () => {
6216-
if (Chunk.isEmpty(leftovers)) {
6217-
return core.void
6218-
}
6219-
if (Option.isNone(pipe(leftovers, Chunk.findFirst(predicate)))) {
6220-
return channel.zipRight(core.write(Chunk.of(leftovers)), core.void)
6223+
const loop = (
6224+
leftovers: Chunk.Chunk<A>
6225+
): Channel.Channel<Chunk.Chunk<Chunk.Chunk<A>>, Chunk.Chunk<A>, E, E, unknown, unknown, R> =>
6226+
core.readWith({
6227+
onInput: (input: Chunk.Chunk<A>) => split(leftovers, input),
6228+
onFailure: core.fail,
6229+
onDone: () => {
6230+
if (Chunk.isEmpty(leftovers)) {
6231+
return core.void
6232+
}
6233+
if (Option.isNone(pipe(leftovers, Chunk.findFirst(predicate)))) {
6234+
return channel.zipRight(core.write(Chunk.of(leftovers)), core.void)
6235+
}
6236+
return channel.zipRight(
6237+
split(Chunk.empty(), leftovers),
6238+
core.void
6239+
)
62216240
}
6222-
return channel.zipRight(
6223-
split(Chunk.empty(), leftovers),
6224-
core.void
6225-
)
6226-
}
6227-
})
6228-
return new StreamImpl(pipe(toChannel(self), core.pipeTo(loop(Chunk.empty()))))
6229-
})
6241+
})
6242+
return new StreamImpl(pipe(toChannel(self), core.pipeTo(loop(Chunk.empty()))))
6243+
}
6244+
)
62306245

62316246
/** @internal */
62326247
export const splitOnChunk = dual<

0 commit comments

Comments
 (0)