abstract class GraphStageLogic extends AnyRef
Represents the processing logic behind a GraphStage. Roughly speaking, a subclass of GraphStageLogic is a collection of the following parts: * A set of InHandler and OutHandler instances and their assignments to the Inlets and Outlets of the enclosing GraphStage * Possible mutable state, accessible from the InHandler and OutHandler callbacks, but not from anywhere else (as such access would not be thread-safe) * The lifecycle hooks preStart and postStop * Methods for performing stream processing actions, like pulling or pushing elements
The operator logic is completed once all its input and output ports have been closed. This can be changed by
setting setKeepGoing
to true.
The postStop
lifecycle hook on the logic itself is called once all ports are closed. This is the only tear down
callback that is guaranteed to happen, if the actor system or the materializer is terminated the handlers may never
see any callbacks to onUpstreamFailure
, onUpstreamFinish
or onDownstreamFinish
. Therefore operator resource
cleanup should always be done in postStop
.
- Source
- GraphStage.scala
- Alphabetic
- By Inheritance
- GraphStageLogic
- AnyRef
- Any
- by any2stringadd
- by StringFormat
- by Ensuring
- by ArrowAssoc
- Hide All
- Show All
- Public
- Protected
Type Members
- class SubSinkInlet[T] extends AnyRef
INTERNAL API
INTERNAL API
This allows the dynamic creation of an Inlet for a GraphStage which is connected to a Sink that is available for materialization (e.g. using the
subFusingMaterializer
). Completion, cancellation and failure of the parent operator is automatically delegated to instances ofSubSinkInlet
to avoid resource leaks.To be thread safe this method must only be called from either the constructor of the graph operator during materialization or one of the methods invoked by the graph operator machinery, such as
onPush
andonPull
. - class SubSourceOutlet[T] extends AnyRef
INTERNAL API
INTERNAL API
This allows the dynamic creation of an Outlet for a GraphStage which is connected to a Source that is available for materialization (e.g. using the
subFusingMaterializer
). Completion, cancellation and failure of the parent operator is automatically delegated to instances ofSubSourceOutlet
to avoid resource leaks.Even so it is good practice to use the
timeout
method to cancel this Outlet in case the corresponding Source is not materialized within a given time limit, see e.g. ActorMaterializerSettings.To be thread safe this method must only be called from either the constructor of the graph operator during materialization or one of the methods invoked by the graph operator machinery, such as
onPush
andonPull
.
Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- def +(other: String): String
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toany2stringadd[GraphStageLogic] performed by method any2stringadd in scala.Predef.
- Definition Classes
- any2stringadd
- def ->[B](y: B): (GraphStageLogic, B)
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toArrowAssoc[GraphStageLogic] performed by method ArrowAssoc in scala.Predef.
- Definition Classes
- ArrowAssoc
- Annotations
- @inline()
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def abortEmitting(out: Outlet[_]): Unit
Abort outstanding (suspended) emissions for the given outlet, if there are any.
Abort outstanding (suspended) emissions for the given outlet, if there are any. This will reinstall the replaced handler that was in effect before the
emit
call.- Attributes
- protected
- final def abortReading(in: Inlet[_]): Unit
Abort outstanding (suspended) reading for the given inlet, if there is any.
Abort outstanding (suspended) reading for the given inlet, if there is any. This will reinstall the replaced handler that was in effect before the
read
call.- Attributes
- protected
- def afterPostStop(): Unit
INTERNAL API
INTERNAL API
- Attributes
- protected[stream]
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def beforePreStart(): Unit
INTERNAL API
INTERNAL API
- Attributes
- protected[stream]
- final def cancel[T](in: Inlet[T], cause: Throwable): Unit
Requests to stop receiving events from a given input port.
Requests to stop receiving events from a given input port. Cancelling clears any ungrabbed elements from the port.
- Attributes
- protected
- final def cancel[T](in: Inlet[T]): Unit
Requests to stop receiving events from a given input port.
Requests to stop receiving events from a given input port. Cancelling clears any ungrabbed elements from the port.
If cancellation is due to an error, use
cancel(in, cause)
instead to propagate that cause upstream. This overload is a shortcut forcancel(in, SubscriptionWithCancelException.NoMoreElementsNeeded)
- Attributes
- protected
- final def cancelStage(cause: Throwable): Unit
Automatically invokes cancel or complete on all the input or output ports that have been called, then marks the stage as stopped.
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @HotSpotIntrinsicCandidate() @native()
- final def complete[T](out: Outlet[T]): Unit
Signals that there will be no more elements emitted on the given port.
Signals that there will be no more elements emitted on the given port.
- Attributes
- protected
- final def completeStage(): Unit
Automatically invokes cancel or complete on all the input or output ports that have been called, then marks the operator as stopped.
- final def conditionalTerminateInput(predicate: () => Boolean): InHandler
Input handler that terminates the state upon receiving completion if the given condition holds at that time.
Input handler that terminates the state upon receiving completion if the given condition holds at that time. The operator fails upon receiving a failure.
- Attributes
- protected
- final def conditionalTerminateOutput(predicate: () => Boolean): OutHandler
Output handler that terminates the state upon receiving completion if the given condition holds at that time.
Output handler that terminates the state upon receiving completion if the given condition holds at that time. The operator fails upon receiving a failure.
- Attributes
- protected
- final def createAsyncCallback[T](handler: Procedure[T]): AsyncCallback[T]
Java API: Obtain a callback object that can be used asynchronously to re-enter the current GraphStage with an asynchronous notification.
Java API: Obtain a callback object that can be used asynchronously to re-enter the current GraphStage with an asynchronous notification. The AsyncCallback.invoke method of the returned AsyncCallback is safe to be called from other threads. It will in the background thread-safely delegate to the passed callback function. I.e. AsyncCallback.invoke will be called by other thread and the passed handler will be invoked eventually in a thread-safe way by the execution environment.
AsyncCallback.invokeWithFeedback has an internal promise that will be failed if event cannot be processed due to stream completion.
This object can be cached and reused within the same GraphStageLogic.
- Attributes
- protected
- final def eagerTerminateInput: InHandler
Input handler that terminates the operator upon receiving completion.
Input handler that terminates the operator upon receiving completion. The operator fails upon receiving a failure.
- Attributes
- protected
- final def eagerTerminateOutput: OutHandler
Output handler that terminates the operator upon cancellation.
Output handler that terminates the operator upon cancellation.
- Attributes
- protected
- final def emit[T](out: Outlet[T], elem: T, andThen: Effect): Unit
- Attributes
- protected
- final def emit[T](out: Outlet[T], elem: T): Unit
Emit an element through the given outlet, suspending execution if necessary.
Emit an element through the given outlet, suspending execution if necessary. This action replaces the OutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal.- Attributes
- protected
- final def emit[T](out: Outlet[T], elem: T, andThen: () => Unit): Unit
Emit an element through the given outlet and continue with the given thunk afterwards, suspending execution if necessary.
Emit an element through the given outlet and continue with the given thunk afterwards, suspending execution if necessary. This action replaces the OutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal (before invoking theandThen
function).- Attributes
- protected
- final def emitMultiple[T](out: Outlet[T], elems: Iterator[T]): Unit
Emit a sequence of elements through the given outlet, suspending execution if necessary.
Emit a sequence of elements through the given outlet, suspending execution if necessary. This action replaces the OutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal.- Attributes
- protected
- final def emitMultiple[T](out: Outlet[T], elems: Iterator[T], andThen: () => Unit): Unit
Emit a sequence of elements through the given outlet and continue with the given thunk afterwards, suspending execution if necessary.
Emit a sequence of elements through the given outlet and continue with the given thunk afterwards, suspending execution if necessary. This action replaces the OutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal (before invoking theandThen
function).- Attributes
- protected
- final def emitMultiple[T](out: Outlet[T], elems: Iterator[T], andThen: Effect): Unit
Java API
Java API
Emit a sequence of elements through the given outlet, suspending execution if necessary. This action replaces the AbstractOutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal.- Attributes
- protected
- final def emitMultiple[T](out: Outlet[T], elems: Iterator[T]): Unit
Java API
Java API
Emit a sequence of elements through the given outlet, suspending execution if necessary. This action replaces the AbstractOutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal.- Attributes
- protected
- final def emitMultiple[T](out: Outlet[T], elems: Iterable[T]): Unit
Emit a sequence of elements through the given outlet, suspending execution if necessary.
Emit a sequence of elements through the given outlet, suspending execution if necessary. This action replaces the OutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal.- Attributes
- protected
- final def emitMultiple[T](out: Outlet[T], elems: Iterable[T], andThen: () => Unit): Unit
Emit a sequence of elements through the given outlet and continue with the given thunk afterwards, suspending execution if necessary.
Emit a sequence of elements through the given outlet and continue with the given thunk afterwards, suspending execution if necessary. This action replaces the OutHandler for the given outlet if suspension is needed and reinstalls the current handler upon receiving an
onPull()
signal (before invoking theandThen
function).- Attributes
- protected
- def ensuring(cond: (GraphStageLogic) => Boolean, msg: => Any): GraphStageLogic
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toEnsuring[GraphStageLogic] performed by method Ensuring in scala.Predef.
- Definition Classes
- Ensuring
- def ensuring(cond: (GraphStageLogic) => Boolean): GraphStageLogic
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toEnsuring[GraphStageLogic] performed by method Ensuring in scala.Predef.
- Definition Classes
- Ensuring
- def ensuring(cond: Boolean, msg: => Any): GraphStageLogic
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toEnsuring[GraphStageLogic] performed by method Ensuring in scala.Predef.
- Definition Classes
- Ensuring
- def ensuring(cond: Boolean): GraphStageLogic
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toEnsuring[GraphStageLogic] performed by method Ensuring in scala.Predef.
- Definition Classes
- Ensuring
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- final def fail[T](out: Outlet[T], ex: Throwable): Unit
Signals failure through the given port.
Signals failure through the given port.
- Attributes
- protected
- final def failStage(ex: Throwable): Unit
Automatically invokes cancel or fail on all the input or output ports that have been called, then marks the operator as stopped.
- final def getAsyncCallback[T](handler: (T) => Unit): AsyncCallback[T]
Obtain a callback object that can be used asynchronously to re-enter the current GraphStage with an asynchronous notification.
Obtain a callback object that can be used asynchronously to re-enter the current GraphStage with an asynchronous notification. The AsyncCallback.invoke method of the returned AsyncCallback is safe to be called from other threads. It will in the background thread-safely delegate to the passed callback function. I.e. AsyncCallback.invoke will be called by other thread and the passed handler will be invoked eventually in a thread-safe way by the execution environment.
In case stream is not yet materialized AsyncCallback will buffer events until stream is available.
AsyncCallback.invokeWithFeedback has an internal promise that will be failed if event cannot be processed due to stream completion.
To be thread safe this method must only be called from either the constructor of the graph operator during materialization or one of the methods invoked by the graph operator machinery, such as
onPush
andonPull
.This object can be cached and reused within the same GraphStageLogic.
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @HotSpotIntrinsicCandidate() @native()
- def getEagerStageActor(eagerMaterializer: Materializer)(receive: ((ActorRef, Any)) => Unit): StageActor
INTERNAL API
INTERNAL API
To be thread safe this method must only be called from either the constructor of the graph operator during materialization or one of the methods invoked by the graph operator machinery, such as
onPush
andonPull
.- Attributes
- protected[pekko]
- Annotations
- @InternalApi()
- final def getHandler(out: Outlet[_]): OutHandler
Retrieves the current callback for the events on the given Outlet
Retrieves the current callback for the events on the given Outlet
- Attributes
- protected
- final def getHandler(in: Inlet[_]): InHandler
Retrieves the current callback for the events on the given Inlet
Retrieves the current callback for the events on the given Inlet
- Attributes
- protected
- final def getStageActor(receive: ((ActorRef, Any)) => Unit): StageActor
Initialize a GraphStageLogic.StageActorRef which can be used to interact with from the outside world "as-if" an pekko.actor.Actor.
Initialize a GraphStageLogic.StageActorRef which can be used to interact with from the outside world "as-if" an pekko.actor.Actor. The messages are looped through the getAsyncCallback mechanism of GraphStage so they are safe to modify internal state of this operator.
This method must (the earliest) be called after the GraphStageLogic constructor has finished running, for example from the preStart callback the graph operator logic provides.
Created GraphStageLogic.StageActorRef to get messages and watch other actors in synchronous way.
The GraphStageLogic.StageActorRef's lifecycle is bound to the operator, in other words when the operator is finished, the Actor will be terminated as well. The entity backing the GraphStageLogic.StageActorRef is not a real Actor, but the GraphStageLogic itself, therefore it does not react to pekko.actor.PoisonPill.
To be thread safe this method must only be called from either the constructor of the graph operator during materialization or one of the methods invoked by the graph operator machinery, such as
onPush
andonPull
.- receive
callback that will be called upon receiving of a message by this special Actor
- returns
minimal actor with watch method
- Attributes
- protected
- final def grab[T](in: Inlet[T]): T
Once the callback InHandler.onPush for an input port has been invoked, the element that has been pushed can be retrieved via this method.
Once the callback InHandler.onPush for an input port has been invoked, the element that has been pushed can be retrieved via this method. After grab has been called the port is considered to be empty, and further calls to grab will fail until the port is pulled again and a new element is pushed as a response.
The method isAvailable can be used to query if the port has an element that can be grabbed or not.
- Attributes
- protected
- final def hasBeenPulled[T](in: Inlet[T]): Boolean
Indicates whether there is already a pending pull for the given input port.
Indicates whether there is already a pending pull for the given input port. If this method returns true then isAvailable must return false for that same port.
- Attributes
- protected
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @HotSpotIntrinsicCandidate() @native()
- final def ignoreTerminateInput: InHandler
Input handler that does not terminate the operator upon receiving completion.
Input handler that does not terminate the operator upon receiving completion. The operator fails upon receiving a failure.
- Attributes
- protected
- final def ignoreTerminateOutput: OutHandler
Output handler that does not terminate the operator upon cancellation.
Output handler that does not terminate the operator upon cancellation.
- Attributes
- protected
- val inCount: Int
- final def isAvailable[T](out: Outlet[T]): Boolean
Return true if the given output port is ready to be pushed.
- final def isAvailable[T](in: Inlet[T]): Boolean
Indicates whether there is an element waiting at the given input port.
Indicates whether there is an element waiting at the given input port. grab can be used to retrieve the element. After calling grab this method will return false.
If this method returns true then hasBeenPulled will return false for that same port.
- Attributes
- protected
- final def isClosed[T](out: Outlet[T]): Boolean
Indicates whether the port has been closed.
Indicates whether the port has been closed. A closed port cannot be pushed.
- Attributes
- protected
- final def isClosed[T](in: Inlet[T]): Boolean
Indicates whether the port has been closed.
Indicates whether the port has been closed. A closed port cannot be pulled.
- Attributes
- protected
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- def materializer: Materializer
The pekko.stream.Materializer that has set this GraphStage in motion.
The pekko.stream.Materializer that has set this GraphStage in motion.
Can not be used from a
GraphStage
constructor. Access to materializer is provided by the pekko.stream.scaladsl.Source.fromMaterializer, pekko.stream.scaladsl.Flow.fromMaterializer and pekko.stream.scaladsl.Sink.fromMaterializer and their corresponding Java API factories.- Attributes
- protected
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @HotSpotIntrinsicCandidate() @native()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @HotSpotIntrinsicCandidate() @native()
- val outCount: Int
- final def passAlong[Out, In <: Out](from: Inlet[In], to: Outlet[Out], doFinish: Boolean = true, doFail: Boolean = true, doPull: Boolean = false): Unit
Install a handler on the given inlet that emits received elements on the given outlet before pulling for more data.
Install a handler on the given inlet that emits received elements on the given outlet before pulling for more data.
doFinish
anddoFail
control whether completion or failure of the given inlet shall lead to operator termination or not.doPull
instructs to perform one initial pull on thefrom
port.- Attributes
- protected
- def postStop(): Unit
Invoked after processing of external events stopped because the operator is about to stop or fail.
Invoked after processing of external events stopped because the operator is about to stop or fail.
- Annotations
- @throws(classOf[Exception])
- def preStart(): Unit
Invoked before any external events are processed, at the startup of the operator.
Invoked before any external events are processed, at the startup of the operator.
- Annotations
- @throws(classOf[Exception])
- final def pull[T](in: Inlet[T]): Unit
Requests an element on the given port.
Requests an element on the given port. Calling this method twice before an element arrived will fail. There can only be one outstanding request at any given time. The method hasBeenPulled can be used query whether pull is allowed to be called or not. This method will also fail if the port is already closed.
- Attributes
- protected
- final def push[T](out: Outlet[T], elem: T): Unit
Emits an element through the given output port.
Emits an element through the given output port. Calling this method twice before a pull has been arrived will fail. There can be only one outstanding push request at any given time. The method isAvailable can be used to check if the port is ready to be pushed or not.
- Attributes
- protected
- final def read[T](in: Inlet[T], andThen: Procedure[T], onClose: Effect): Unit
Java API: Read an element from the given inlet and continue with the given function, suspending execution if necessary.
Java API: Read an element from the given inlet and continue with the given function, suspending execution if necessary. This action replaces the InHandler for the given inlet if suspension is needed and reinstalls the current handler upon receiving the
onPush()
signal (before invoking theandThen
function).- Attributes
- protected
- final def read[T](in: Inlet[T])(andThen: (T) => Unit, onClose: () => Unit): Unit
Read an element from the given inlet and continue with the given function, suspending execution if necessary.
Read an element from the given inlet and continue with the given function, suspending execution if necessary. This action replaces the InHandler for the given inlet if suspension is needed and reinstalls the current handler upon receiving the
onPush()
signal (before invoking theandThen
function).- Attributes
- protected
- final def readN[T](in: Inlet[T], n: Int, andThen: Procedure[List[T]], onClose: Procedure[List[T]]): Unit
Java API: Read a number of elements from the given inlet and continue with the given function, suspending execution if necessary.
Java API: Read a number of elements from the given inlet and continue with the given function, suspending execution if necessary. This action replaces the InHandler for the given inlet if suspension is needed and reinstalls the current handler upon receiving the last
onPush()
signal (before invoking theandThen
function).- Attributes
- protected
- final def readN[T](in: Inlet[T], n: Int)(andThen: (Seq[T]) => Unit, onClose: (Seq[T]) => Unit): Unit
Read a number of elements from the given inlet and continue with the given function, suspending execution if necessary.
Read a number of elements from the given inlet and continue with the given function, suspending execution if necessary. This action replaces the InHandler for the given inlet if suspension is needed and reinstalls the current handler upon receiving the last
onPush()
signal.If upstream closes before N elements have been read, the
onClose
function is invoked with the elements which were read.- Attributes
- protected
- final def setHandler(out: Outlet[_], handler: OutHandler): Unit
Assigns callbacks for the events for an Outlet
Assigns callbacks for the events for an Outlet
- Attributes
- protected
- final def setHandler(in: Inlet[_], handler: InHandler): Unit
Assigns callbacks for the events for an Inlet
Assigns callbacks for the events for an Inlet
- Attributes
- protected
- final def setHandlers(in: Inlet[_], out: Outlet[_], handler: InHandler with OutHandler): Unit
Assign callbacks for linear operator for both Inlet and Outlet
- final def setKeepGoing(enabled: Boolean): Unit
Controls whether this operator shall shut down when all its ports are closed, which is the default.
Controls whether this operator shall shut down when all its ports are closed, which is the default. In order to have it keep going past that point this method needs to be called with a
true
argument before all ports are closed, and afterwards it will not be closed until this method is called with afalse
argument or the operator is terminated viacompleteStage()
orfailStage()
.- Attributes
- protected
- final def stageActor: StageActor
- def stageActorName: String
Override and return a name to be given to the StageActor of this operator.
Override and return a name to be given to the StageActor of this operator.
This method will be only invoked and used once, during the first getStageActor invocation whichc reates the actor, since subsequent
getStageActors
calls function likebecome
, rather than creating new actors.Returns an empty string by default, which means that the name will a unique generated String (e.g. "$$a").
- Attributes
- protected
- def subFusingMaterializer: Materializer
An pekko.stream.Materializer that may run fusable parts of the graphs that it materializes within the same actor as the current GraphStage (if fusing is available).
An pekko.stream.Materializer that may run fusable parts of the graphs that it materializes within the same actor as the current GraphStage (if fusing is available). This materializer must not be shared outside of the GraphStage.
- Attributes
- protected
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- GraphStageLogic → AnyRef → Any
- final def totallyIgnorantInput: InHandler
Input handler that does not terminate the operator upon receiving completion nor failure.
Input handler that does not terminate the operator upon receiving completion nor failure.
- Attributes
- protected
- final def tryPull[T](in: Inlet[T]): Unit
Requests an element on the given port unless the port is already closed.
Requests an element on the given port unless the port is already closed. Calling this method twice before an element arrived will fail. There can only be one outstanding request at any given time. The method hasBeenPulled can be used query whether pull is allowed to be called or not.
- Attributes
- protected
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
Deprecated Value Members
- def finalize(): Unit
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.Throwable]) @Deprecated
- Deprecated
(Since version 9)
- def formatted(fmtstr: String): String
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toStringFormat[GraphStageLogic] performed by method StringFormat in scala.Predef.
- Definition Classes
- StringFormat
- Annotations
- @deprecated @inline()
- Deprecated
(Since version 2.12.16) Use
formatString.format(value)
instead ofvalue.formatted(formatString)
, or use thef""
string interpolator. In Java 15 and later,formatted
resolves to the new method in String which has reversed parameters.
- def →[B](y: B): (GraphStageLogic, B)
- Implicit
- This member is added by an implicit conversion from GraphStageLogic toArrowAssoc[GraphStageLogic] performed by method ArrowAssoc in scala.Predef.
- Definition Classes
- ArrowAssoc
- Annotations
- @deprecated
- Deprecated
(Since version 2.13.0) Use
->
instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.